Reference: http://blog.csdn.net/slvher/article/details/42497781
This article describes the relationship between these several and the differences between them systematically. Interested friends can go to the above link to view the original text, here I copy the original text as follows (if there is infringement, notice immediately deleted)
====================================================================
When reading the source code for some open source Python libraries, you will often see syntax sugars similar to @staticmethod or @classmethod or @property before the member functions of a class. Essentially, they are function decorators, but they are usually used to decorate class member functions.
This note is intended to illustrate the use of these syntactic sugars, which can be referred to in the explanation of common function adorner syntax.
Before interpreting these adorner functions, first analyze the normal member functions.
1. Ordinary member functions of the class
For a Python class, the first parameter of its ordinary class member function defaults to the current class instance, and the usual definition form is an example:
[Python]
Class C:def __init__ (self): # # NOTICE: Creating an instance without passing in the argument will cause an error; "Self" is only a conventional parameter name, non-grammatical hard rules
Pass
We can view the function __init__ () via print c.__init__:
[Python]
>>> class C (): ... def __init__ (self): ... Pass ... >>> print c.__init__
In summary, for ordinary member functions of a class, before creating a concrete instance of the class, they are
Unbound Method, when called by the class name (such as C.Fn ()), an error is made, and when the class instance is created, they are
instance of bound method, which can only be invoked through an instance (inst = C (); Inst.fn ()).
The reason for the unbound method function call error is related to the lookup rule of the function name when Python is implemented at the bottom. As you can see from the example code above, the __init__ () function implements the __get__ () method by default, and according to the python underlying rules, when an object (all objects in Python) implements the _get__ ()/__set__ ()/__delete__ () Any of these 3 method, it becomes a descriptor that supports descriptor protocal. When calling c.__init__ (of course, this is what the Python interpreter does for us, but this does not change the fact that __init__ is actually a normal class function), according to the descriptor invoking rule, it will be converted to type (c). __dict_ In the form of _[' __init__ '].__get__ (c, type (c)), it is visible that the invocation actually occurs similar to c.__init__ (c), where instance C of Class C is passed as a 1th argument to the normal class member function. So
when you define a class normal member function, you need at least the self parameter, and the ordinary member function of the class must be called through the class instance, not directly through the class name.
Regarding the descriptor protocol mentioned above and its effect on the OBJ attribute lookup rules, it is strongly recommended to read this document Descriptor HowTo Guide. It is no exaggeration to say that understanding descriptor is a great help in understanding the underlying behavior of Python code.
2. @classmethod
According to the Python documentation, Classmethod (FN) indicates that the function FN is a function of a class rather than an instance of a class, and in syntax it requires that the function signature of FN must have at least 1 arguments, and when the function is called, the interpreter passes the class as the 1th argument to FN. Examples are as follows:
[Python]
>>> class C (): ... def fn_classmethod (x): ... Print x ... fn = Classmethod (fn_classmethod) ... >>> C.Fn
As can be seen, when the call Classmethod () converts Fn_classmethod to class method, we can invoke it directly through C.Fn, and of course, through the C (). FN () call.
It is also important to note that when C.Fn () is called, the argument of the Fn_classmethod () unique parameter x is indeed Class C (that is, the __main__ printed out in the example. C), the parameter is automatically passed in by the interpreter.
In Python syntax, @classmethod is a syntactic sugar that implements the automatic invocation of Classsmethod (Fn_classmethod), which implements the same functionality as the example code above, but looks leaner and pythonic:
[Python]
>>> class C ():
... @classmethod # # Python's decorator syntax guarantees automatic invocation of Classmethod (FN)
... def fn (x):
... print X
...
>>> C.Fn
>>> C.Fn () __main__. C
Typical use cases for Classmethod:
1) directly use the class to invoke the function without using the class instance
2) More gracefully implement the construction of instances of a class (similar to Factory Pattern)
Typically, class instances are constructed by the __init__ () of the class that the interpreter calls automatically, but with Classmethod you can implement some preprocessing logic before the interpreter calls __init__, and then pass the preprocessed arguments into the class's constructor to create the class instance. The Fromkeys () method supported by the Dict type is implemented with Classmethod, which constructs a new dict instance with the current keys of the Dict instance. In the final part of the document Descriptor HowTo Guide gives its corresponding Python pseudo-code, which is interesting to look at.
Another typical case for implementing class instance constructs is to refer to this question and answer post on StackOverflow. The best answer author of the post gives a typical scenario where a class instance can be constructed using a non-Classmethod method, but with the help of Classmethod syntax, it can be more elegant (a. Compared with the __init__ construction example, the Classmethod method also ensures that the code reuse of the construction logic and the implementation is more streamlined, such as parsing date_as_string for (year, month, day) code can be reused; b. It does not have to be called by an instance of the class, and a new instance can be constructed by invoking the class directly; C. It is more in line with OOP than defining a global function that implements the same function. When a base class is inherited, the Classmethod defined in the base class are also inherited into the inheriting class.
3. @staticmethod
According to the Python documentation, Staticmethod (FN) indicates that the function fn is a static method of the class. specifically to the definition of a function within a class definition, if the function wants to declare a static member, simply precede its definition with the line "@staticmethod", and use the adorner syntax sugar to achieve staticmethod (cls.fun) purpose. Examples are as follows:
[Python]
Class C (object):
@staticmethod
def f (arg1, arg2, ...):
...
Similar to Classmethod's decorator syntax sugar, the @staticmethod automatically calls Staticmethod (f).
The semantics of class static methods in Python are similar to C++/java, where a static member of a class belongs to the class itself, not to an instance of the class, and it cannot access the properties of the instance (data member or member function). When a function defined as Staticmethod is called, the interpreter does not automatically pass in the parameters of the class or class instance, and its actual argument list is consistent with the argument list that was explicitly passed in at the time of invocation.
Typical application scenarios for Staticmethod:
Consider defining a function of a class as a staticmethod of a class if it does not involve operations related to the class instance. For example, according to business logic, the global function can be encapsulated into a class and declared as Staticmethod, so that it seems more consistent with the idea of OOP, specific examples can refer to this blog. Of course, this is just an OOP approach to encapsulation, not meant to meet the global function must do this, need to look at personal habits or business needs.
emphasize again: a function defined as a staticmethod type, preferably in a function body that does not involve operations related to class instances (including creating class instances or accessing instance properties), because once a class instance is involved it means that the instance names are hard-coded, and in the case where the class is inherited, Functions that call these staticmethod types create a base class or access a base class property, which is usually not the behavior expected by the business. Specific case can refer to stackoverflow this question and answer post of the 2nd high-ticket answers.
4. @property
Based on the description of the Python document, property ([fget[, fset[, fdel[, Doc]]]) creates and returns a Property object for the New-style class, created from the parameters passed in (Fget/fset/fdel). It can determine whether external callers have read/write/delete permissions on certain properties of the New-style class. Take the demo as an example of the official website document:
[python] view plain copy print?
- Class C (object): # # Notice:property only valid for new style classes
- def __init__ (self):
- self._x = None
- def getx (self):
- Return self._x
- def setx (self, value):
- self._x = value
- def delx (self):
- Del self._x
- X = Property (Getx, Setx, Delx, "I ' m the ' X ' property.")
In the example above, X is the Property object of Class C, and since it was created with 3 function objects, a read/write/delete operation on self._x can be achieved by accessing the attribute. Specifically, when you call C (). x, the interpreter eventually calls Getx; when you call C (). x = value, the interpreter eventually calls Setx; when you call Del C (). x, the interpreter eventually calls Delx.
Because the 1th parameter of property () is Fget, it makes it easy to implement a class attribute with only Read-only permissions:
[python] view plain copy print?
- >>> class C (object):
- ... def __init__ (self):
- ... self._name = ' name '
- ... @property
- ... def get_name (self):
- ... return Self._name
- ...
- ...
- >>> C = C ()
- >>> C.get_name
- ' Name '
- >>> c.get_name = ' new name '
- Traceback (most recent):
- File "
- Attributeerror:can ' t set attribute
Of course, the "read-only" mentioned here simply means that the property name will not be re-bound to the new object by the assignment operation . If the property name is initially bound to a mutable object (such as list or dict), the contents of its bound object can be modified by the property name even if it is decorated with @property.
If you want to modify or delete the properties of a class instance through an instance object of the class, you need the following code to implement:
[python] view plain copy print?
- >>> class C (object):
- ... def __init__ (self):
- ... self._name = ' name '
- ... @property
- ... def name (self):
- ... return Self._name
- ... @name. Setter
- ... def name (self, value):
- ... self._name = value
- ... @name. deleter
- ... def name (self):
- ... del self._name
- ...
- >>> C = C ()
- >>> C.name
- ' Name '
- >>> c.__dict__
- {' _name ': ' Name '}
- >>> c.name = ' new name '
- >>> c.__dict__
- {' _name ': ' New Name '}
- >>> C.name
- ' New name '
- >>> del c.name
- >>> c.__dict__
- {}
In the code above, @property, @name. Setter and @name.deleter are the adorner syntax sugars, wherein: @name. The name in the setter refers to the @property decorated object (that is, the property (name) Returns an object named name but Type Property object), the setter is the built-in function of this property named Name, which is intended to be passed Name.setter (name) Provides the Property object with the ability to modify the properties of its owning class. @name. Deleter the same.
As to the origins of the Function setters () and deleter () supported by the Property object, document Descriptor HowTo Guide gives the python pseudo code of the property class at the bottom of the property principle, which is worth intensive reading.
As you can see from the pseudo-code, the property class implements the __get__ (), __set__ (), and __delete__ () methods, which means that the property class is a data protocol that follows descriptor descriptor. According to document Descriptor HowTo Guide's instructions for invoking descriptors, data descriptor affects the interpreter's lookup chain for attribute names, specifically, When C.name is called in the above code, the interpreter converts it to type (c). __dict__[' name '].__get__ (c, type (c)) (Note: Through print type (c). __dict__ can verify that Name does exist in Dict), so the converted call chain invokes the __get__ () method of the Property object, and, based on the property's implementation pseudo-code, in __get__ () will eventually invoke the name () function corresponding to Class C.
The process described above is the principle behind property magic.
Of course, the Python pseudo-code logic of the property needs to be studied carefully for real understanding.
@property can be used in this scenario in addition to the read-only permission feature that implements the property:
Class attributes have been exposed to external callers, but due to business requirements, business logic needs to be modified for this attribute (such as adding boundary judgments or modifying attribute calculations, etc.), then introducing property () or @property syntax sugar can guarantee the code's back compatibility while modifying the logic. External callers do not need to modify the calling method. The specific case can refer to the scene mentioned in this blog.
Resources
1. Several advanced syntax concepts for Python: lambda expressions && closures && Decorators
2. Descriptor HowTo Guide
3. Stackoverflow:python @classmethod and @staticmethod for beginner?
4. Python Docs:classmethod
5. Python Docs:staticmethod
6. The definitive Guide "on" To use static, class or abstract methods in Python
7. Newfound love of @staticmethod in Python
8. Objects and Classes in Python:decorators
9. Python Docs:property ()
. Python Property
====================== EOF =====================
Python decorator Syntax sugar (@classmethod @staticmethod @property @name.) Principle Analysis and Application scenario