Methods are tied on demand, every time you access it.
Access to the function name calls the descriptor protocol , which returns the associated method on the function objects.
A related method is a thin shell around a function object; it saves a reference to the original function and instance. When a method object is called, it, in turn, passes the function call, with the instance inserted as the first argument.
Methods are not created when an instance is created, so there is no need for additional a-priori memory.
You can re-create the steps manually:
>>> class A: ... def __init__(self, name): ... self.name = name ... def foo(self): ... print(self.name) ... >>> a = A('One') >>> a.foo <bound method A.foo of <__main__.A object at 0x100a27978>> >>> a.foo.__self__ <__main__.A object at 0x100a27978> >>> a.foo.__func__ <function A.foo at 0x100a22598> >>> A.__dict__['foo'] <function A.foo at 0x100a22598> >>> A.__dict__['foo'].__get__(a, A) <bound method A.foo of <__main__.A object at 0x100a27978>> >>> A.__dict__['foo'].__get__(a, A)() One
Each time only a method object is recreated; main function remains stable:
>>> a.foo is a.foo False >>> b = A('Two') >>> b.foo is a.foo False >>> b.foo.__func__ is a.foo.__func__ True
This architecture also makes classmethod , staticmethod and property . You can create your own descriptors by creating a number of interesting binding methods.
source share