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

Source: Internet
Author: User
In Python, the descriptor is also called a descriptor. the descriptor can implement access control over object attributes. next we will analyze the role and usage of the descriptor in Python, A descriptor is an object attribute with "binding behavior". its access control is overwritten by the descriptor protocol method. These methods are _ get _ (), _ set _ (), and _ delete __(). Objects with these methods are called descriptors.

By default, access control over properties is obtained from the object Dictionary (_ dict _) (get), set (set), and delete (delete) it. For example,. the search order of x is,. _ dict _ ['x'], and then type (). _ dict _ ['x'], and then find the parent class of type (a) (excluding metaclass )). if the found value is a descriptor, Python will call the descriptor method to override the default control behavior. Where this overwrite occurs in this search process depends on which descriptor method is defined. Note that the descriptor only works in the new class. (New classes are classes inherited from type or object)

The descriptor is powerful and widely used. The descriptor is exactly the implementation mechanism behind properties, instance methods, static methods, class methods, and super. The descriptor is widely used in Python 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 daily Python programming.

Descriptor protocol

descr.__get__(self, obj, type=None) --> valuedescr.__get__(self, obj, value) --> Nonedescr.__delete__(self, obj) --> None

If an object is a descriptor and is treated as an object attribute (important), the default search behavior is overwritten.

If an object defines both _ get _ and _ set __, it is called data descriptor. Only the descriptor of _ get _ is defined as non-data descriptor.

The difference between data descriptor and non-data descriptor lies in the priority of the dictionary relative to the instance. if the instance Dictionary has an attribute with the same name as the descriptor, and if the descriptor is data descriptor, data descriptor is preferred. For non-data descriptor, the attribute in the dictionary is preferred.

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. name = 'KK ',. _ dict _ contains the name attribute. Next, set __

def __set__(self, obj, value):  self.name = value ... do somethinga = A()print a.__dict__  # print {}print a.name    # print minka.name = 'kk'    print a.__dict__  # print {}print a.name    # print kk

Because the access attribute priority of data descriptor is higher than that of the instance dictionary, a. _ dict _ is empty.

Descriptor Call
The descriptor can be called directly like this: d. _ get _ (obj)

However, it is more common that the descriptor is automatically called During attribute access. For example, obj. d will find d in the obj Dictionary. if d defines the _ get _ method, d. _ get _ (obj) is called based on the following priority rules.

The call details depend on whether obj is a class or an instance. In addition, the descriptor only works for new objects and new classes. Classes inherited from objects are called new classes.

For objects, the method object. _ getattribute _ () converts B. convert x to type (B ). _ dict _ ['x']. _ get _ (B, type (B )). The specific implementation is based on the following priority: the data descriptor takes precedence over the instance variable, and the instance variable takes precedence over the non-data descriptor, __getattr _ () method (if the object contains) has the lowest priority. The complete c language implementation can be viewed in PyObject_GenericGetAttr () in Objects/object. c.

For the class, the method type. _ getattribute _ () converts B. x is changed to B. _ dict _ ['x']. _ get _ (None, B ). It is described in Python as follows:

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

Important points:

  • The descriptor is called because _ getattribute __()
  • The override _ getattribute _ () method will prevent normal descriptors from calling.
  • _ Getattribute _ () is only available for instances of new classes.
  • Object. _ getattribute _ () and type. _ getattribute _ () have different calls to _ get _ ().
  • The data descriptor always takes precedence over the instance Dictionary.
  • The non-data descriptor may be overwritten by the instance Dictionary. (The non-data descriptor is not as preferred as the instance Dictionary)
  • The returned object of super () also has a custom _ getattribute _ () method to call the descriptor. Call super (B, obj ). m () will first be in obj. _ class __. in _ mro _, find the base class A next to B and return. _ dict _ ['M']. _ get _ (obj, ). If it is not a descriptor, m is returned as is. If m is not found in the instance dictionary, the object. _ getattribute _ () will be called in the future. (Translator's note: find in the next base class in _ mro)

Note: In Python 2.2, if m is a descriptor, super (B, obj). m () will only call method _ get __(). In Python 2.3, non-data descriptors (unless they are old classes) are also called. The implementation details of super_getattro () are as follows: Objects/typeobject. c, [del] An equivalent Python implementation is implemented in Guido's Tutorial [/del] (Translator's note: The original sentence has been deleted and is retained for your reference ).

The above shows that the descriptor mechanism is implemented in the object, type, and super _ getattribute _ () method. Classes derived from objects automatically inherit this mechanism, or they have meta-classes with similar mechanisms. Similarly, you can override the _ getattribute _ () method of the class to disable the descriptor behavior of the class.

Descriptor example
The following code defines a data descriptor, which prints a message each time get and set. Override _ getattribute _ () is another method that allows all attributes to possess this behavior. However, the descriptor is useful when monitoring specific attributes.

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(10, 'var "x"')  y = 5>>> m = MyClass()>>> m.xRetrieving var "x"10>>> m.x = 20Updating var "x">>> m.xRetrieving var "x"20>>> m.y5

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

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.