Based on my understanding of Python's data model, and specifically the subsection "Instance Methods", whenever you read an attribute whose value is of type "user-defined function", some magic kicks in and you get a bound instance method instead of the actual, original function. That magic is why you don't explicitly pass the self
parameter when you're calling a method.
But then, I would expect to be able to replace an object's method with a function with the same signature:
class Scriptable: def __init__(self, script = None): if script is not None: self.script = script # replace the method def script(self): print("greetings from the default script") >>> scriptable = Scriptable() >>> scriptable.script() greetings from the default script >>> def my_script(self): ... print("greetings from my custom script") ... >>> scriptable = Scriptable(my_script) >>> scriptable.script() Traceback (most recent call last): ... TypeError: script() takes exactly 1 positional argument (0 given)
I'm creating an instance of Scriptable
, and setting its script
attribute to a user-defined function with a single parameter, just like what's defined in the class. So when I read the scriptable.script
attribute, I would expect the magic to kick in and give me a bound instance method that takes no parameters (just like I get when I didn't replace script
). Instead, it seems to be giving back the exact same function I passed in, self
parameter and all. The method-binding magic isn't happening.
Why does the method-binding magic work when I define a method inside the class declaration, but not when I assign the attribute? What makes Python treat these situations differently?
I'm using Python3 if it makes any difference.
To pass an object as an argument we write the object name as the argument while calling the function the same way we do it for other variables. Syntax: function_name(object_name); Example: In this Example there is a class which has an integer variable 'a' and a function 'add' which takes an object as argument.
In JavaScript, functions are called Function Objects because they are objects. Just like objects, functions have properties and methods, they can be stored in a variable or an array, and be passed as arguments to other functions.
You can call a function inside an object by declaring the function as a property on the object and invoking it, e.g. obj. sum(2, 2) . An object's property can point to a function, just like it can point to a string, number or other values. Copied!
In Python, we can assign a function to a variable. And using that variable we can call the function as many as times we want. Thereby, increasing code reusability. Simply assign a function to the desired variable but without () i.e. just with the name of the function.
Python object() Function The object() function returns an empty object. You cannot add new properties or methods to this object. This object is the base for all classes, it holds the built-in properties and methods which are default for all classes.
Here is how you do it:
import types class Scriptable: def __init__(self, script = None): if script is not None: self.script = types.MethodType(script, self) # replace the method def script(self): print("greetings from the default script")
As ba__friend noted in the comments, methods are stored on the class
object. A descriptor on the class object returns functions as bound methods when you access the attribute from a instance.
When you assign a function to a instance
nothing happens special happens, so you have to wrap the function yourself.
Thanks to Alex Martelli's answer here is another version:
class Scriptable: def script(self): print(self) print("greetings from the default script") def another_script(self): print(self) print("greetings from the another script") s = Scriptable() s.script() # monkey patching: s.script = another_script.__get__(s, Scriptable) s.script()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With