In front of the descriptor, this thing actually and Java setter,getter a bit like. But what does this descriptor have to do with the functional approach we started with earlier?
All functions can be descriptor, because it has __get__ methods.
Copy Code code as follows:
>>> def hello ():
Pass
>>> dir (Hello)
[' __call__ ', ' __class__ ', ' __delattr__ ', ' __dict__ ', ' __doc__ ', ' <span style= ' color: #ff0000; >__get__</span>
', ' __getattribute__ ',
' __hash__ ', ' __init__ ', ' __module__ ', ' __name__ ', ' __new__ ',
' __reduce__ ', ' __reduce_ex__ ', ' __repr__ ', ' __setattr__ ', ' __str__ ', ' func_closure ',
' Func_code ', ' func_defaults ', ' func_dict ', ' func_doc ', ' func_globals ', ' func_name '
>>>
Note that the function object has no __set__ and __del__ methods, so it is a non-data descriptor.
The method is actually a function, as follows:
Copy Code code as follows:
>>> class T (object):
def hello (self):
Pass
>>> t.__dict__[' Hello ']
<function Hello at 0x00cd7eb0>
>>>
Alternatively, we can think of a method as a special function, except that they exist in the class, and when we get the function property, we return not the function itself (such as the <function hello at 0x00cd7eb0> above), but the return value of the __get__ method of the function. Then the definition of class T above:
>>> T.hello Gets the hello attribute of T, which is found from T's __dict__ according to the lookup strategy, and finds <function hello at 0x00cd7eb0>, but does not return directly to < function Hello at 0x00cd7eb0>, because it has a __get__ method, so it returns the result of the __get__ (None, T) that called it: a unbound method.
<unbound Method t.hello>
>>> f = t.__dict__[' Hello '] #直接从T的__dict__中获取hello, does not perform a lookup strategy and returns directly to <function hello at 0x00cd7eb0>
Copy Code code as follows:
>>> F
<function Hello at 0x00cd7eb0>
>>> t = t ()
>>> T.hello #从实例获取属性, returns the result of calling the __get__ (T, t) of <function Hello at 0x00cd7eb0>: a bound method.
Copy Code code as follows:
<bound method T.hello of <__main__. T Object at 0x00cdad10>>
>>>
To confirm what we said above, continue with the following code (f or above <function Hello at 0x00cd7eb0>):
Copy Code code as follows:
>>> f.__get__ (None, T)
<unbound Method t.hello>
>>> f.__get__ (T, T)
<bound method T.hello of <__main__. T Object at 0x00cdad10>>
Great!
To sum up:
1. All functions have the __get__ method
2. When a function is in the __dict__ of a class, this function can be considered a method that, when obtained by a class or instance, returns not the function itself but its __get__ method return value.
I admit I may have misled you into thinking that the method is a function, a special function. In fact, there is a difference between the method and the function, exactly: The method is the method, the function is the function.
Copy Code code as follows:
>>> type (f)
<type ' function ' >
>>> type (T.hello)
<type ' Instancemethod ' >
>>> type (T.hello)
<type ' Instancemethod ' >
>>>
Functions are function types, and method is Instancemethod (this is the normal instance approach, followed by the reference to Classmethod and Staticmethod).
About unbound method and bound method, say two more words. In the C implementation, they are the same object (they are all instancemethod types), so let's look at what's inside of them first.
Copy Code code as follows:
>>> dir (T.hello)
[' __call__ ', ' __class__ ', ' __cmp__ ', ' __delattr__ ', ' __doc__ ', ' __get__ ', ' __getattribute__ ',
' __hash__ ', ' __init__ ', ' __new__ ', ' __reduce__ ', ' __reduce_ex__ ', ' __repr__ ', ' __setattr__ ',
' __str__ ', ' im_class ', ' im_func ', ' im_self '
__call__ that they are callable objects, and we can also guess that the implementation of this __call__ should roughly be: To turn another function (which we expect, such as Hello above) and take the object as the first argument.
The attention is im_class,im_func,im_self. We are not unfamiliar with these things, in T.hello, they represent T,hello (here is the function Hello) and T, which are stored in t.__dict__. With these we can roughly imagine how pure Python implements a instancemethod:).
In fact, there are several built-in functions are related to descriptor, the following simple to say.
Classmethod
Classmethod can convert a function to a class method, the first implied parameter of the class method is the class itself (the first implied parameter of the normal method is the instance itself), the class method can be invoked from the class, or it may be invoked from the instance (normal methods can only be invoked from the instance).
Copy Code code as follows:
>>> class T (object):
def hello (CLS):
print ' Hello ', cls
Hello = Classmethod (hello) #两个作用: Change the hello to a class method while hiding the hello as the normal method
>>> t = t ()
>>> T.hello ()
Hello <class ' __main__. T ' >
>>> T.hello ()
Hello <class ' __main__. T ' >
>>>
Note: Classmethod is a class, not a function. The Classmethod class has a __get__ method, so the above T.hello and T.hello get the Classmethod method return value that is actually __get__
Copy Code code as follows:
>>> T.hello
<bound method Type.hello of <class ' __main__. T ' >>
>>> type (T.hello)
<type ' Instancemethod ' >
>>> T.hello
<bound method Type.hello of <class ' __main__. T ' >>
>>> type (T.hello)
<type ' Instancemethod ' >
>>>
As you can see from the above, T.hello and T.hello are instancemethod types and are bound to T. This means that the Classmethod __get__ method returns a Instancemethod object. In the previous analysis of Instancemethod, we should be able to infer that T.hello's im_self is T,im_class is type (T is an instance of type), and Im_func is the function hello
Copy Code code as follows:
>>> t.hello.im_self
<class ' __main__. T ' >
>>> T.hello.im_class
<type ' type ' >
>>> T.hello.im_func
<function Hello at 0x011a40b0>
>>>
Exactly the same! So it's not difficult to implement a pure Python Classmethod:
Staticmethod
Staticmethod can convert a function to a static method, and the static method has no implied first argument.
Copy Code code as follows:
Class T (object):
def hello ():
print ' Hello '
Hello = Staticmethod (hello)
>>> T.hello () #没有隐含的第一个参数
Hello
>>> T.hello
<function Hello at 0x011a4270>
>>>
T.hello directly returns a function. The __get__ method of guessing Staticmethod class should be to return directly to the object itself.
There is also a property, similar to the top two, it is a data descriptor.