I was reading the python docs and stumbled upon the following lines:
It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods; this only happens when the function is an attribute of the class.
Please, someone explain what does that mean in plain english.
I’m going to introduce some shorthand notation:
let ‘user-defined functions‘ be denoted by f,
let ‘class instance‘ be denoted by ci while class denoted simply by c. Obviously(?), ci = c(), with some abuse of notation.
Also, allow membership statements to be recast in simple set notation eg ‘user-defined functions which are attributes of a class instance‘ in shorthand is ‘vf: fεa(ci)‘, where v: ‘for all‘ and where ‘a‘ is the shorthand for (set of) attributes (eg of a class or class instance) and ‘ε’ denotes the set membership function.
Also, the process of binding a function is described in shorthand by ci.f(*args) or c.f(*args) => f(ci, *args) or f(c, *args) (the former referring to an instance method call while the later referring to a class method call)
Using the newly introduced shorthand notation, does the quote from the docs imply that
vf: fεa(c), c.f(*args) => f(c, *args) is a true statement
while
vf: fεa(ci), ci.f(*args) => f(ci, *args) is false?
Answer
Setting a User Defined Method to be an Attribute of Class, The Wrong Way
Consider the following example class A
and function f
:
class A: pass def f(self): print("I'm in user-defined function") a = A()
The function f
is defined separately and not inside the class.
Let’s say you want to add function f
to be an instance method for a
object.
Adding it, by setting f
as a
attribute, won’t work:
import types class A: pass def f(self): print("I'm in user-defined function") a = A() a.f = f # <function f at 0x000002D81F0DED30> print(a.f) # TypeError: f() missing 1 required positional argument: 'self' # a.f()
Because function f
is not bound to the object a
.
That is why when calling a.f()
it shall raise an error regarding the missing argument (if f
has been bounded to a
, that object a
was the missing argument self
).
This part is what the docs referred at:
It is also important to note that user-defined functions which are attributes of a class instance are not converted to bound methods.
Of course, all this has not to happen if function f
has been defined inside class A
, that’s what the following part from the docs states:
…this only happens when the function is an attribute of the class.
Setting a User Defined Method to be an Attribute of Class, The Right Way
To add function f
to object a
you should use:
import types class A: pass def f(self): print("I'm in user-defined function") a = A() a.f = types.MethodType( f, a ) # <bound method f of <__main__.A object at 0x000001EDE4768E20>> print(a.f) # Works! I'm in user-defined function a.f()
Which bounds the user-defined method f
to instance a
.