This article summarizes the differences and relationships between bound method objects (Bound method object) and unbound methods objects (Unboud object) in Python. The main purpose is to distinguish between these two highly confusing concepts, and by the way, the static methods, class methods, and instance methods of Python are explained.
OK, here we go.
1. A "murder" caused by a method
A function defined in a class is called a method Example:
>>>class Foo(object):... def foo():... print ‘call foo‘
And then the confusing place comes: when you try to use the class name. Method name when calling function Foo, the following error occurs
>>> Foo.foo()Traceback (most recent call last): "<stdin>", line 1, in <module>TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
Look at the error message The discovery requires an instance of Foo (instance) to invoke, OK, so the call is as follows:
>>> Foo().foo()Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: foo() takes no arguments (1 given)
-.-!!!
Estimated temper bad see do here want to squalling.
Because, literally, foo (). Foo () does not pass any parameters, but the error message is displayed (1 given).
In Python everything is object, method is function, so let's take a closer look at the function object foo
method Foo.foo>>>> Foo().foo<bound method Foo.foo of <__main__.Foo object at 0x7ff33b424d50>>
Yi ~, found an interesting phenomenon:
When you get the Class function property Foo from the class name Foo, we get the unbound method object, which gets the function property Foo of the class by instance Foo (), which is the bound method object.
Take a look at the types of these two objects:
type(Foo.foo)<type ‘instancemethod‘>>>> type(Foo().foo)<type ‘instancemethod‘>
So we have a bigger question: Why are the same instance methods (Instancemethod), and the different ways of getting them, which leads to the acquisition of different objects?
2. How did the Bound/unbound method come from?
Let's take a layer to uncover the veil of this bound/unbound method. First, we know that for a class, its properties are stored in the __dict__ dictionary, which is:
>>> Foo. __dict__dict_proxy ({ __dict__ ': <attribute ' __dict__ ' of ' Foo ' Objects>, ' __module__ ': __main_ _ ', ' foo ': <function foo at 0x< Span class= "Hljs-number" >7ff33b42a 5f0>, ' __weakref__ ': < Attribute ' __weakref__ ' of ' Foo ' Objects>, ' __doc__ ': None})
In which we saw ' foo ': <function foo at 0x7ff33b42a5f0>. Then use the dictionary to view foo:
>>> Foo.__dict__[‘foo‘]<function foo at 0x7ff33b42a5f0>
You can see that Foo is a function object, according to the last example in the previous section, we found that Foo has a binding behavior.
Use descriptors (links with translations) in Python to represent object properties with binding behavior, and use descriptor protocol methods to control access to properties that have binding behavior, including: __get__ (), __set__ (), and __delete__ ().
Based on this difficult-to-understand description, we can boldly guess that Foo's attribute foo is a descriptor that controls access to Foo through the __get__ () method.
According to the Descriptor Protocol method descr.__get__ (self, obj, Type=none)--value, we try the following:
>>> Foo.__dict__[‘foo‘].__get__(None,Foo)<unbound method Foo.foo>
We were surprised to see that the result was the same as the one we saw in the previous section!
This is by no means accidental.
In fact, according to the official document description, when calling Foo.foo, Python starts with the lookup chain from foo.__dict__[' foo ') and then looks for the type (foo). __dict__[' foo ', looking up for type (foo) All of the base classes. Foo.foo will be converted to foo.__dict__[' foo '].__get__ (None,foo).
that is, we use Foo.foo in code to actually be converted to
foo.__dict__[' Foo '].__get__ (none,foo)
for descr.__get__ based on descriptor protocol methods (self, obj , Type=none)--The argument list of value, because its self parameter is given none here, so there is no given instance, so it is considered unbound (unbound)
(which is, of course, an easy-to-understand description, and the underlying mechanism is here)
The simple reasoning is that if the self parameter is given an instance object, then the bound method is obtained, as follows.
>>> Foo.__dict__[‘foo‘].__get__(Foo(),Foo)<bound method Foo.foo of <__main__.Foo object at 0x7ff33b424d50>>
Therefore, it can be understood as follows:
When a function property is obtained through a class, the resulting non-binding method object gets the binding method object when it obtains the function property through the instance.
3. Methods, static method and class method
If you have experience using the Python method, then be sure to pay attention to the use of self, see the following example:
>>>ClassFoo (Object): .....DefFoo():.. print' Call foo ' ...DefFoo_one(Self): ... print' Call Foo_one ' ...>>> Foo.foo () Traceback (most recent call last): File"<stdin>", line1,In <Module>Typeerror:unbound Method Foo () must is called with Foo instance as first argument (got nothing instead)>>> foo (). Foo () Traceback (most recent call last): File " <stdin> ", line 1, in <module>typeerror:foo () takes no arguments ( 1 given) >>> Foo.foo_one () Traceback (most recent call last): File " <stdin> ", line 1, in <module>typeerror:unbound method Foo_one () must is called with Foo Instance as first argument (got nothing instead) >>> Foo (). Foo_one () Call Foo_one
This example defines two Method:foo () and Foo_one (self).
As you can see, the same error is reported when you call the method name () by using the same class name. However, when using the instance name. Method Name () call, Foo_one is callable successfully.
Why is it?
The reason for this is that when you call Foo (). Foo_one (), Python makes the following modifications:
>>> Foo.foo_one(Foo())call foo_one
The instance foo () is passed in as the first argument, so the function foo_one (self) call succeeds. This also explains why the Foo (). Foo () call was unsuccessful. Because Foo is defined as foo (), when you call Foo (). Foo (), Python makes the following modifications:
>>> Foo.foo(Foo())Traceback (most recent call last): File "<stdin>", line 1, in <module>TypeError: foo() takes no arguments (1 given)
A parameter foo () is passed in, so there is an error with Foo () takes no arguments (1 given).
I have seen some people put foo () This parameter list does not have self in the method called the class method, and the method with self is called an instance method, according to the above description can be found that this division is wrong.
So, is there a class method in Python?
The answer is, there is. So how do you define a class method?
Pyhon class method
Or use the example above
>>> class Foo(object): ... @classmethod #定义类方法要点1... def foo(cls): #定义类方法要点2... print ‘call foo‘... >>> Foo.foo()call foo>>> Foo().foo()call foo
There are two points to be aware of when defining class methods: 1. Add @classmethod;2. A class method that is defined so that the CLS parameter is added can be called by the class name. Method name () or by instance. Method Name ().
As you can see here, there are two parameters, self or CLS, that define methods in Python. The method that is qualified by self must use an instance to invoke.
The natural question is, can you define a method that does not include self and CLS? As in the first example, Foo (). The answer is yes, the way is to add @staticmethod modifier.
This method, modified by the @staticmethod modifier, is called a static method
Python static method
In addition to the class method, there are static methods, see the following example:
>>> class Foo(object):... @staticmethod... def foo():... print ‘call foo‘... >>> Foo.foo()call foo>>> Foo().foo()call foo
Static methods can be called by the class name. Method name () and instance. Method Name (). View the type results as follows:
type(Foo.foo)<type ‘function‘>
As you can see, the type of the static method is function, and the type of the class method is Instancemethod.
Summarize
Finally, let's summarize:
From the point of view of the Python method definition, there are three types:
1. The first parameter is self;
2. The first parameter is a CLS;
3. Parameters do not contain self or CLS-free
For the first method, you must pass the instance. Method Name () or class name. Method Name (instance) of the call;
For the second, you can pass an instance. Method name () or class name. The method name () is called in the form of the class name. Method name (instance);
For the third, the method is the normal function, but it must pass through the instance. Method Name () or class name. Method Name () and cannot be called by another form
Reproduced Python method binding Some sort of--unbound/bound methods object