In-depth analysis of the role and usage of the descriptor descriptor in Python

Source: Internet
Author: User
In general, a descriptor is an object property with a "binding behavior" (object attribute), and its access control is overridden by the descriptor protocol method. These methods are __get__ (), __set__ (), and __delete__ (). Objects with these methods are called descriptors.

The default access control for a property is obtained (get) from the object's Dictionary (__dict__), set, and delete (delete). For example, A.x's lookup order is, a.__dict__[' x '], then type (a). __dict__[' X '], and then find the parent class of type (a) (not including the Meta-Class (Metaclass)). If the value found is a descriptor, Python will tune Use the descriptor's method to override the default control behavior. Where this rewrite occurs depends on which descriptor method is defined. Note that the descriptor will only work if it is in the new class. (A new class is a class that inherits from type or object)

The descriptor is powerful and widely used. Descriptors are the implementation mechanisms behind attributes, instance methods, static methods, class methods, and Super. The descriptor is widely used in Python itself to implement the new class introduced in Python 2.2. The descriptor simplifies the underlying C code and provides a flexible set of new tools for the daily programming of Python.

Descriptor protocol

Descr.__get__ (self, obj, Type=none)--valuedescr.__get__ (self, obj, value)--nonedescr.__delete__ (self, obj)- -None

An object that, if it is a descriptor, overrides the default lookup behavior when it is treated as an object property (very important).

If an object defines both __get__ and __set__, it is called data descriptor. A descriptor that defines only __get__ is called Non-data descriptor.

The difference between data descriptor and Non-data descriptor is that the precedence of the dictionary relative to the instance, if the instance dictionary has a property with the same name as the descriptor, if the descriptor is data descriptor, takes precedence over data descriptor. If it is non-data descriptor, use the properties in the dictionary first.

Class B (object):  def __init__ (self):    self.name = ' Mink '  def __get__ (self, obj, Objtype=none):    return Self.nameclass A (object):  name = B () a = A () print a.__dict__  # print {}print a.name    # print minka.name = ' KK ' 
  print a.__dict__  # print {' name ': ' KK '}print a.name    # Print KK

Here B is a non-data descriptor so when a.name = ' kk ', a.__dict__ will have the name attribute, then set it to __set__

def __set__ (self, obj, value):  self.name = value ... do somethinga = A () print a.__dict__  # print {}print a.name< c12/># Print minka.name = ' KK '    print a.__dict__  # print {}print a.name    # Print KK

Because the data descriptor Access attribute has a higher precedence than the instance's dictionary, a.__dict__ is empty.

Invocation of the Descriptor
The descriptor can be called directly: d.__get__ (obj)

However, the more common scenario is that the descriptor is called automatically when the property is accessed. For example, OBJ.D will find D in the dictionary of obj, and if D defines the __get__ method, then d.__get__ (obj) will be called based on the following precedence rules.

The details of the invocation depend on whether obj is a class or an instance. In addition, descriptors only work for modern objects and new classes. Classes that inherit from object are called modern classes.

For objects, the method object.__getattribute__ () turns b.x into type (b). __dict__[' x '].__get__ (b, type (b)). The implementation is based on the order of precedence: The data descriptor takes precedence over the instance variable, the instance variable takes precedence over the non-data descriptor, and the __getattr__ () method (if contained in the object) has the lowest precedence. The complete C language implementation can be viewed pyobject_genericgetattr () in objects/object.c.

For classes, the method type.__getattribute__ () turns b.x into b.__dict__[' x '].__get__ (None, B). To describe in Python is:

def __getattribute__ (self, key):  "emulate Type_getattro () in objects/typeobject.c"  v = object.__getattribute_ _ (Self, key)  if Hasattr (V, ' __get__ '):    Return of v.__get__ (None, self)  return V

One of the important points:

    • The descriptor is called because __getattribute__ ()
    • Overriding the __getattribute__ () method prevents normal descriptor calls
    • __GETATTRIBUTE__ () Only available for instances of the new class
    • OBJECT.__GETATTRIBUTE__ () and type.__getattribute__ () do not have the same call to __get__ ()
    • The data descriptor always takes precedence over the instance dictionary.
    • A non-data descriptor may be overridden by an instance dictionary. (Not a data descriptor is preferable to an instance dictionary)
    • Super () The returned object also has a custom __getattribute__ () method to invoke the descriptor. Calling super (B, obj). m () first finds the base class A next to B in obj.__class__.__mro__, and then returns a.__dict__[' m '].__get__ (obj, A). Returns m if it is not a descriptor. If M is not found in the instance dictionary, the object.__getattribute__ () lookup continues to be called back. (Translator Note: The next base class in __mro__ is found)

Note: in Python 2.2, if M is a descriptor, super (B, obj). m () will only call Method __get__ (). In Python 2.3, a non-data descriptor (unless it is a legacy Class) is also called. Super_getattro () Implementation details in: OBJECTS/TYPEOBJECT.C, [del] an equivalent Python implementation in Guido ' s Tutorial [/del] (translator Note: This sentence has been deleted from the original, reserved for everyone to refer to).

The mechanism shown above is implemented in the __getattribute__ () method of object, type, and super. Classes derived from object automatically inherit this mechanism, or they have a meta-class with a similar mechanism. Similarly, the __getattribute__ () method of the class can be overridden to turn off the descriptor behavior of this class.

Descriptor examples
A data descriptor is defined in the following code, and each get and set prints a message. overriding __getattribute__ () is another method that enables all properties to have this behavior. However, the descriptor is useful for monitoring specific properties.

Class Revealaccess (object): "" "  A data descriptor that sets and returns values    normally and prints A message loggin G 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.xretrieving var "x" 10>>> m.x = 20Updating var "x" >>> M.xretr ieving var "x" 20>>> m.y5

This protocol is very simple and offers exciting possibilities. Some uses are so common that they are packaged as separate functions. Like properties, methods (bound and unbound method), static methods and class methods are based on the descriptor protocol.

  • Related Article

    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.