I noticed that if I define a class attribute equal to a function when I create an instance of that class the attribute becomes a bound method. Can someone explain me the reason of this behaviour?
In [9]: def func():
...: pass
...:
In [10]: class A(object):
....: f = func
....:
In [11]: a = A()
In [12]: a.f
Out[12]: <bound method A.func of <__main__.A object at 0x104add190>>
In [13]: a.f()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-13-19134f1ad9a8> in <module>()
----> 1 a.f()
global a.f = <bound method A.func of <__main__.A object at 0x104add190>>
TypeError: func() takes no arguments (1 given)
You assigned a function to the attribute A.f
(the attribute f
of the class A
). The attribute A.f
was defined as part of the class. It is a function, so it is by default an instance method of that class.
Creating an instance (named a
) of class A
causes that instance to have an attribute f
, and you access that by the name a.f
. This is a bound method (cause it's bounded to the object a
; further explanation here).
Every instance method, when it is called, automatically receives the instance as its first argument (conventionally named self
). Other types of method are possible: - see class methods and static methods.
For this reason the error says that func
takes no arguments (as it's defined as def func():
) but received 1 (self
).
To do what you want, you should tell python that you're using a static method
def func():
pass
class A(object):
f = staticmethod(func)
Python is not a message based OO system1. Instead, similar to JavaScript, properties are resolved to first-class functions and then invoked; the behavior differs a bit in the mechanics of such, as discovered.
In Python the requirement is that methods have at least one parameter, normally called self
, that will be automatically supplied the associated instance when it is invoked as a method.
Furthermore (and perhaps to the point of the question), Python does not differentiate between using def f..
or f = some_func()
when establishing instance member bindings; arguably this matches behavior outside of classes.
In the example, assigning the function to the instance 'makes it expect to be treated like an instance method'. It is the exact same - parameterless - function called in both cases; only the future usage of such is relevant.
Now, unlike JavaScript, Python handles methods and object association through the concept of bound methods - functions resolved as methods are always 'bound'.
The behavior of a.f
returning a bound method - function that will automatically supply the bound object to the first parameter as self
- is done independently of the source of the function. In this case that means the parameterless function cannot be used when it is 'bound' as it does not accept a self
parameter.
As a demonstration, the following will fail in the same way because the source underlying method does not meet the minimum requirements of accepting the instance as an argument:
g = a.f
g()
In this case calling g()
is equivalent to calling func(a)
.
1 For comparison, Java, C#, Ruby, and SmallTalk are message based OO systems - in these an object is told to invoke a method by a 'name', instead of resolving a method (or function) as a value which can be invoked.
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