How does Python create instance methods through class methods?

  python

The following is a passage in Python 3.x language reference to the effect that it is understandable, but I cannot write such an example. please ask the great god to give an example consistent with this passage:

When an instance method object is derived from a class method object, the “class instance” stored inSelfwill actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function.

In fact, you will understand this part by doing your own experiments.


Let’s start with the original text and discuss it in two paragraphs. The first paragraph says:

When an instance method object is called, the underlying function (__func__) is called, inserting the class instance (__self__) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1).

The first paragraph of the original text said, when ainstance method objectWhen called,__func__The first parameter of is passed in firstclass instanceAfter the call, then give an example:

x.f(1) == C.f(x,1)  # x is an instance of C

We use the following example to illustrate that here we have a classDemoThere is a function under him.fooAnd functionBar.

DemoClass:

class Demo:
 
 def foo(self, *args):
 Return 'callfood by instance' plus repr(self) plus 'withargs' plus repr(args)
 
 @classmethod
 def bar(cls, *args):
 Return 'Call bar by class' plus repr(cls) plus 'withargs' plus repr(args)

In fact:

  1. Python forfooA that generates aGeneral functionThis function will beDemo.fooReference.

  2. When we writedemo.fooPython will create abound method object:demo.fooThis method object is a bound method. What is bound? Of course it is bindingDemoThis instance, sodemo.foo.__self__Will refer toDemoAt the same time Python will alsoDemo.fooWrite it down indemo.foo.__func__China.

  3. So when thisdemo.fooWhen called (demo.foo(1,2,3)), he will actually calldemo.foo.__func__And withdemo.foo.__self__(in fact, that isDemoSelf) as the first parameter.

To show with the class we wrote, his example becomes:

x.f(1)   ==    C.f(x, 1)
 demo.foo(1) == Demo.foo(demo, 1) == demo.foo.__func__(demo.foo.__self__, 1)

LookCode:

demo  = Demo()
 
 print('=== Demo start ===\n')
 
 print('demo.foo', ':', demo.foo)
 print('    [type             ] ', type(demo.foo))
 print('    [demo.foo.__self__] ', demo.foo.__self__)
 print('    [demo.foo.__func__] ', demo.foo.__func__)
 print('    [demo.foo(1,2,3)  ] ', demo.foo(1,2,3))
 print()
 
 print('Demo.foo', ':', Demo.foo)
 print('    [type                 ] ', type(Demo.foo))
 print('    [Demo.foo(demo, 1,2,3)] ', Demo.foo(demo, 1,2,3))
 print()
 
 print('demo.foo.__func__', ':',  demo.foo.__func__,)
 print('    [type                          ] ', type(demo.foo.__func__))
 print('    [demo.foo.__func__(demo, 1,2,3)] ', demo.foo.__func__(demo, 1,2,3))
 print()
 
 print('Demo.foo is demo.foo.__func__ --> ', Demo.foo is demo.foo.__func__)

test result:

=== Demo start ===
 
 demo.foo : <bound method Demo.foo of <__main__.Demo object at 0x7f413db47fd0>>
 [type             ]  <class 'method'>
 [demo.foo.__self__]  <__main__.Demo object at 0x7f413db47fd0>
 [demo.foo.__func__]  <function Demo.foo at 0x7f413db41840>
 [demo.foo(1,2,3)  ]  Call foo by instance<__main__.Demo object at 0x7f413db47fd0>with args(1, 2, 3)
 
 Demo.foo : <function Demo.foo at 0x7f413db41840>
 [type                 ]  <class 'function'>
 [Demo.foo(demo, 1,2,3)]  Call foo by instance<__main__.Demo object at 0x7f413db47fd0>with args(1, 2, 3)
 
 demo.foo.__func__ : <function Demo.foo at 0x7f413db41840>
 [type                          ]  <class 'function'>
 [demo.foo.__func__(demo, 1,2,3)]  Call foo by instance<__main__.Demo object at 0x7f413db47fd0>with args(1, 2, 3)
 
 Demo.foo is demo.foo.__func__ -->  True

Then look at the second paragraph:

When an instance method object is derived from a class method object, the “class instance” stored in self will actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function.

The second paragraph is to the effect that when the instance method object comes from the class method object, there isSelfInside’sClass instanceIt will beClassItself, then gave another example:

x.f(1) == C.f(1) == f(C,1)  # x is an instance of C

We also use examples to illustrate:

  1. Python generates for barDemo.bar, he is a fromclass method objectThebound method object, originallyDemo.barJust likeDemo.fooIt is also a general Python function, but through the modifier (@classmethodModifier), he became a bound method object, to observe the original general function, only inDemo.bar.__func__See, at the same time he boundDemoClass, soDemo.bar.__self__Will refer toDemoClass.

  2. So whenDemo.barWhen called (Demo.bar(1)He will actually callDemo.bar.__func__And withDemo.bar.__self__(in fact, that isDemoSelf) as the first parameter.

To show with the class we wrote, his example becomes:

x.f(1)   ==    C.f(1)   == f(C, 1)
 demo.bar(1) == Demo.bar(1) == Demo.bar.__func__(Demo, 1) == Demo.bar.__func__(Demo.bar.__self__, 1)

Test code:

demo  = Demo()
 
 print('=== Demo start ===\n')
 
 print('Demo.bar', ':', Demo.bar)
 print('    [type             ] ', type(Demo.bar))
 print('    [Demo.bar.__self__] ', Demo.bar.__self__)
 print('    [Demo.bar.__func__] ', Demo.bar.__func__)
 print('    [Demo.bar(1,2,3)  ] ', Demo.bar(1,2,3))
 print()
 
 print('Demo.bar(1)               ', Demo.bar(1))
 print('demo.bar(1)               ', demo.bar(1))
 print('Demo.bar.__func__(Demo, 1)', Demo.bar.__func__(Demo, 1))

test result:

=== Demo start ===
 
 Demo.bar : <bound method type.bar of <class '__main__.Demo'>>
 [type             ]  <class 'method'>
 [Demo.bar.__self__]  <class '__main__.Demo'>
 [Demo.bar.__func__]  <function Demo.bar at 0x7f413db41950>
 [Demo.bar(1,2,3)  ]  Call bar by class <class '__main__.Demo'>with args(1, 2, 3)
 
 Demo.bar(1)                Call bar by class <class '__main__.Demo'>with args(1,)
 demo.bar(1)                Call bar by class <class '__main__.Demo'>with args(1,)
 Demo.bar.__func__(Demo, 1) Call bar by class <class '__main__.Demo'>with args(1,)

Conclusion:

  1. In Python3, there are two kinds of funciton in class, one is the general functionabject, the other is the boundmethodbject.

  2. Instance method is a general function that binds the method object composed of instance, and class mehtod is a general function that binds the method object composed of class

  3. When bound method is called, it is actually the most primitive function (recorded in__func__, but takes the bound object as the first parameter (noted in__self__Chinese).


Reference material:

Difference between methods and functions
Different way to create an instance method object in Python