Does Python create an entire related method for each new instance?

I am reading about classes in Python (3.4) and from what I understand it seems that each new object has its own instances of related methods.

class A: def __init__(self, name): self.name = name def foo(self): print(self.name) a = A('One') b = A('Two') print(a.foo == b.foo) 

The result of this is False .

It seems to me a waste of memory. I thought that internally a.foo and b.foo would somehow internally point to one function in memory: A.foo where self would be passed as an instance of the class.

I believe that this cannot be easily implemented in the language.

Does each new instance also contain new instances of its related methods?

If so, doesnโ€™t this degrade performance and give reason to create new objects more carefully than in other languages, where methods are "divided" between objects, as in Java?

+6
source share
2 answers

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.

+15
source

The demystification check that I did shows that the functions are stored in the dictionary of the main class A and distributed among the instances. But then the last two lines show as soon as we associate the methods that they use at a unique memory address.

 class A: def __init__(self, name): self.name = name def foo(self): print(self.name) a = A('One') b = A('Two') d=a.__dict__ D=A.__dict__ print('dict a:', d) print('dict A:', D) print(D['foo']) #<function A.foo at 0x000001AF4258CC80> # both next __func__ point to the parent dict print(a.foo.__func__) #<function A.foo at 0x000001AF4258CC80> print(b.foo.__func__) #<function A.foo at 0x000001AF4258CC80> print(a.foo) print(b.foo) #already bound on unique address print(a.foo==b.foo) 

Full conclusion:

 dict a: {'name': 'One'} dict A: {'__module__': '__main__', '__init__': <function A.__init__ at 0x000001AF425D3730>, 'foo': <function A.foo at 0x000001AF425D3620>, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None} <function A.foo at 0x000001AF425D3620> <function A.foo at 0x000001AF425D3620> <function A.foo at 0x000001AF425D3620> <bound method A.foo of <__main__.A object at 0x000001AF425E21D0>> <bound method A.foo of <__main__.A object at 0x000001AF42375C50>> False 
0
source

All Articles