Classmethod one use is to create an optional class constructor

Source: Internet
Author: User

Definition and Introduction
In general, descriptor is an object bound to a special behavior property that is overloaded by the method defined by the descriptor protocol when it accesses it. These methods are __get__, __set__ and __delete__. If an object defines either method, the object is called Descriptor.
The default behavior of accessing an object's properties is a get, set, or delete property in the object dictionary. For example, the a.x lookup path starts with a.__dict__[' x '], then type (a). __dict__[' X '], and continues to find the ancestor class of type (a) (excluding Metaclass). If the lookup value is an object that defines the descriptor method, Python may override the default behavior to call the Descriptor method instead. Where this behavior occurs depends on what descriptor methods are defined. Note that descriptor is only valid in a new type of object or class (The new class is a class that inherits from Object or type)
Descriptor is a powerful, versatile protocol. It is the mechanism behind the implementation of properties, method, static methods, class methods and super () functions. It is used by Python itself to implement the new class introduced in version 2.2. Descriptors simplifies the underlying C code and provides a flexible set of tools for Python programs.
Descriptor Protocol
Descr.__get__ (self, obj, Type=none)--value

Descr.__set__ (self, obj, value)--None

descr.__delete__ (self, obj)--None

That's all that stuff. The object that defines any of these methods is considered to be descriptor and overloaded as the default behavior when the property is looked up.
If the object defines both __get__ and __set__, it is considered to be a data descriptor. If only the definition of __get__ is called the Non-data descriptor (usually used for methods, but can also do other purposes)
The difference between data and Non-data descriptor is that the entity in the instance's dictionary is concerned about how to overload. If there is an entity with the same name as data decriptor in the instance dictionary, data descriptor takes precedence. If this is the same name as Non-data descriptor, the dictionary entity takes precedence.
To create a read-only data descriptor, define both __get__ and __set__, and then throw a Attributeerror exception in the __set__. Defining a __set__ method that throws an exception can guarantee that it is data descriptor.
Invoking descriptors
Descriptor can be called directly with its method name, such as d.__get__ (obj).
In addition, the more common invocation method is called automatically by accessing the property. For example, OBJ.D appears to look for D in the dictionary of obj. If d defines the __get__ method, d.__get__ (obj) is called based on the following precedence rules.
The details of the invocation depend on whether obj is an object or a class. In any case, descriptor only works in the new class. If a class is a subclass of object, it is a new class.
For an object, the mechanism is object.__getattribute__, which transforms b.x into type (b). __dict__[' x '].__get__ (b, type (b)). The execution sequence follows a priority chain: data The descriptor is superior to the instance variable, the instance variable is better than the non-datadescriptor, and if __getattr__ is given its lowest priority. The C implementation can be found in the object/object.c pyobject_generigetattr ().
For classes, the mechanism is type.__getattribute__, which transforms b.x into b.__dict__[' x '].__get__ (None, B). In Python, it looks something like this:
def __getattribute__ (self, key):
"Emulate Type_getattro () in Objects/typeobject.c"
v = object.__getattribute__ (self, key)
If Hasattr (V, ' __get__ '):
Return v.__get__ (None, self)
Return V
The key points to remember are:
Descriptors is called by __getattribute__.
Overloading __getattribute__ prevents automatic calls to descriptor
__GETATTRIBUTE__ are only new classes and objects.
object.__getattribute__ and type.__getattribute__ call __get__ are not the same
Data descriptor Overloaded Instance dictionaries
Non-data descriptor will be overloaded by the instance dictionary
The object returned by super () is called descriptors, and there is a custom __getattribute__. Call Super (B, obj). m () will search for obj.__class__.__mro__, first base class A, immediately B then return a.__dict__[' m '].__get (obj, A). If M is not descriptor, the returned m is unchanged. If it is not in the dictionary, M re-finds it using object.__getattribute__.
Note that in python2.2, __get__ () is called only if M is Data descriptor,super (b,obj). m (). In python2.3, Non-data descriptor is also called, unless the old type (classic) class is involved. Implementation details are available in the objects/typeobject.c Super_getattro (), and the equivalent Python version can be found in the Guido Guide.
The above details show that the descriptor mechanism and details are embedded into the __getattribute__ method of object, type and super (). Classes inherit these mechanisms when classes inherit from object or their meta-class can provide similar functionality. Similarly, classes can close descriptor calls by overloading __getattribute__.
Descriptor Example
The following code creates a class that is data descriptor, which prints a message each time a get or set is made. If you want to change all property behavior, overloading __getattribute__ is another method. However, descriptor is useful if you want to monitor only a few of the selected properties.
Class Revealaccess (object):
"" "A data descriptor that sets and returns values
Normally and prints a message logging their access.
"""
def __init__ (self, initval=none, name= ' var '):
Self.val = Initval
Self.name = Name
def __get__ (self, obj, ObjType):
print ' Retrieving ', self.name
Return Self.val
def __set__ (self, obj, val):
print ' Updating ', self.name
Self.val = Val
>>> class MyClass (object):
x = revealaccess ("var" x "')
y = 5
>>> m = MyClass ()
>>> m.x
retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
retrieving var "x"
20
>>> M.Y
5

The descriptor protocol is simple and offers exciting possibilities. Several use cases are so generic that they are packaged as separate invocation of the number of calls. Properties, bound and unbound methods, static methods, and class methods are all based on the descriptor protocol.

Properties
Calling property () is a neat way to build data descriptor (Access attributes trigger functions). It is marked by:
Property (Fget=none, Fset=none, Fdel=none, Doc=none) and property attribute
A typical application is shown below:
Class C (object):
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.")
The property () Python version implements:
Class Property (object):
"Emulate Pyproperty_type () in Objects/descrobject.c"
def __init__ (self, fget=none, Fset=none, Fdel=none, Doc=none):
Self.fget = Fget
Self.fset = Fset
Self.fdel = Fdel
self.__doc__ = doc
def __get__ (self, obj, Objtype=none):
If obj is None:
return self
If Self.fget is None:
Raise Attributeerror, "unreadable attribute"
return Self.fget (obj)
def __set__ (self, obj, value):
If Self.fset is None:
Raise Attributeerror, "can ' t set attribute"
Self.fset (obj, value)
def __delete__ (self, obj):
If Self.fdel is None:
Raise Attributeerror, "can ' t delete attribute"
Self.fdel (obj)
The built-in property () is useful when the user interface is used to ensure that the attributes are available or to be interfered with later changes.
For example, a spreadsheet class intends to pass the cell (' B10 '). Value accesses the values of a cell, and the program requires that the cell's value be recalculated after each access, however, the programmer does not want the client code to access the property directly. The workaround is to wrap the attribute into a property data descriptor.
Class Cell (object):
. . .
def getvalue (self, obj):
"Recalculate cell before returning value"
Self.recalc ()
Return Obj._value
Value = Property (GetValue)
Functions and Methods
The object-oriented nature of Python is built on a function-based environment. Because of the Non-data descriptor, the functions and methods are perfectly unified.
The class dictionary stores functions into methods. In a class definition, the definition method uses Def and lambda, just as you would create a function. The only difference is that the first parameter is reserved for the object instance. By Python convention, an instance reference is called self, but it can also be called this or another variable name.
To support method invocation, a function containing __get__ () is bound into a method. This means that all functions are non-data descriptor, whether they return a bound method or a non-binding method depending on whether the caller is an object or a class. The Python version is as follows:
Class Function (object):
. . .
def __get__ (self, obj, Objtype=none):
"Simulate Func_descr_get () in Objects/funcobject.c"
return types. Methodtype (self, obj, objtype)
Show how function descriptor actually works in the explanation:
>>> class D (object):
def f (self, x):
return x
>>> d = d ()
>>> d.__dict__[' F '] # Stored internally as a function
<function F at 0x00c450702881064151>
>>> D.F # Get from a class becomes an unbound method
<unbound Method d.f>
>>> D.F # Get from an instance becomes a bound method
<bound method D.F of <__main__. D Object at 0x00b18c90>>
The output shows that the bound and unbound methods are two different types. And they may be so implemented, in the actual implementation of C code (OBJECTS/CLASSOBJEC.C Pymethod_type), is an object, two different representations, depending on whether the Im_self field is set or not.
Similarly, the effect of invoking a method is dependent on im_self. If Im_self has a value (binding), the original function (where Im_func exists) is called and the first argument is set to an instance. If unbound, all parameters are passed to the original function without changes. The actual C implementation code Instancemethod_call looks only slightly more complex, including some type checking.
Static Methods and Class Methods
Non-data Descriptor provides a simple mechanism to bind a function into a method
For reuse, the function contains a __get__ (), so when accessed as a property, they are transformed into a method. Non-data Descriptor converts OBJ.F (*args) to F (obj, *args), and calls Klass.f (*args) into call F (*args).
This chart summarizes these two variants:
Transformation called from the Object called from a Class
function f (obj, *args) f (*args)
Staticmethod f (*args) f (*args)
Classmethod f (Type (obj), *args) F (Klass, *args)
The static method returns the following function without making any changes. Calling C.F or C.F is equivalent to finding object.__getattribute__ (C, "F") or object.__getattribute__ (C, "F"). As a result, the function becomes the same regardless of whether it is accessed from an object or class.
The method benefit of static methods is that you do not need to reference the self variable
For example, a statistical package might contain a container class that processes experimental data. class provides a normal way to calculate mean, median, and other data-based statistical formulas. However, some functions may be conceptually related to data independent, such as ERF (x) is a convenience translator in statistical work but not directly dependent on data. It can call S.erf (1.5) from the object and call Sample.erf (1.5) from the class.
>>> class E (object):
def f (x):
Print X
f = Staticmethod (f)
>>> print E.F (3)
3
>>> print E (). f (3)
3
Python version Staticmethod is as follows:
Class Staticmethod (object):
"Emulate Pystaticmethod_type () in Objects/funcobject.c"
def __init__ (self, f):
SELF.F = f
def __get__ (self, obj, Objtype=none):
Return SELF.F
Unlike the static method, class method has a class reference in the argument list beforehand before calling the function. The format is the same regardless of whether the caller is an object or a class.
>>> class E (object):
def f (Klass, X):
return klass.__name__, X
f = Classmethod (f)
>>> print E.F (3)
(' E ', 3)
>>> print E (). f (3)
(' E ', 3)
This behavior is useful when a function requires only a class reference and does not care about any instance data. One use of Classmethod is to create an optional class constructor. In python2.3, use Classmethod Dict.fromkeys () to create a new dictionary from the keys list, as follows:
Class Dict:
. . .
Def Fromkeys (Klass, Iterable, Value=none):
"Emulate Dict_fromkeys () in Objects/dictobject.c"
D = Klass ()
For key in iterable:
D[key] = value
Return D
Fromkeys = Classmethod (Fromkeys)
You can now create a new dict as follows:
>>> Dict.fromkeys (' Abracadabra ')
{' A ': none, ' r ': None, ' B ': none, ' C ': None, ' d ': none}
Python version Classmethod is as follows:
Class Classmethod (object):
"Emulate Pyclassmethod_type () in Objects/funcobject.c"
def __init__ (self, f):
SELF.F = f
def __get__ (self, obj, Klass=none):
If Klass is None:
Klass = Type (obj)
def newfunc (*args):
Return Self.f (Klass, *args)
Return Newfunc

Classmethod one use is to create an optional class constructor

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.