Python Descriptor (Descriptor) Miscellaneous

Source: Internet
Author: User

Transferred from: https://blog.tonyseek.com/post/notes-about-python-descriptor/

The descriptor syntax feature introduced by Python is really very yellow and violent, and I think this is one of the core members of the Python object model. The Compact of Python language design is largely due to it. So write a note that records everything I know about descriptors.

Low level-Pure descriptor

Pure descriptors are pure, based on three special methods of __get__ , __set__ , __delete__ defined in the class. Any one of these three methods is implemented, and instances of this class have some special features.

Suppose you now have a class mydescriptor, which has a descriptor implementation. Instantiate the Mydescriptor (my_descriptor) and then use the instance as the class property of the other class Spam.

ClassMydescriptor(Object):Def__get__(Self,Subject_instance,Subject_class):Return(Self,Subject_instance,Subject_class)Def__set__(Selfsubject_instancevalue): print  "%r %r %r " (selfsubject_ Instancevalue) my_descriptor = span class= "n" >mydescriptor () class spam (object): my = my_descriptor spam = spam ()        

Bar Mydescriptor Instance as Spam a class property named  my  , Spam class properties  my   's access is overloaded. &NBSP;spam.my  , spam.my   and &NBSP;spam.my = 123   are no longer directly in &NBSP;spam.__dict_ _ Get and add values on  , instead call &NBSP;my_descriptor.__get__ (None, Spam)  , < TT class= "docutils literal" >my_descriptor.__get__ (spam, spam)   and  my_ descriptor.__set__ (spam, 123)  . If &NBSP;mydescriptor   implements &NBSP;__delete__  , then  del spam.my   will also be overloaded to   my_descriptor.__delete__ (spam)  .

So I understand that in order to correspond to the "meta-Class" (Meta-class), the descriptor actually implements the "meta-attribute" (Meta-attribute). This overload allows you to define many object property specifications that have special behaviors, and many of the built-in object model members of Python are implemented in this way.

High-level #0-from "function" to "method"

One of the important functions of descriptors in the Python object model is to implement the object method. We all know that the methods in Python have these features:

      The
    • method itself is a normal function with at least one parameter, and the No. 0 parameter bit self points to the instance, similar to the C + +  const t* This   pointer.
    • A function of a method exists in the namespace of a class in the form of a normal function, such as &NBSP;spam   &NBSP;egg   The original form of the method is &NBSP;spam.__dict__[' egg ']   this function. When
    • accesses this function through an instance, it is similar to &NBSP;spam (). Egg   Way , the resulting is no longer  spam.__dict__[' egg '] The original function saved in  , It is a packaged "bound method". This object still has  __call__   can be called, but compared to the original function it wraps, this object accepts a call when the parameter list is missing a parameter. This is a similar  functools.partial (raw_function, self)   effect, the original function has been done partial function processing, The default is to bind the instance object to the No. 0 parameter bit (where self is usually located);
    • Strangely, if you define a function object that implements the &NBSP;__call__  , put it in the class attribute, it does not exhibit the "Bind Self" feature.

I've been wondering about this for a while, thinking it's a grammar-level behavior. Until I saw the author of the Flask, Jinja 2, Armin Ronacher, a Presentation, I didn't know that the Method was not a syntactic-level feature at all, but was implemented by descriptors.

What I've been ignoring is that a def -defined Python function or a lambda expression has a __get__ implementation In addition to the __call__ implementation. That is, all Python functions are by default a descriptor. The attribute of this descriptor has no meaning outside of the object context of "class", but as long as it is in the class, it will be overloaded with My_instance.my_method as the other descriptors do myclass.__dict__[' My_ Method '].__get__ (my_instance, MyClass) . The "bind self parameter" process is exactly the __get__ behavior, resulting in the equivalence of Spam.egg (1, 2, 3) and spam.egg (spam, 1, 2, 3) .

Knowing this, my thinking is much clearer. The "method" is not a special class property, but the implementation of defining a special class property is the descriptor in the Python object model. The understanding of this is also very useful, Armin Ronacher's presentation mentions the ability to use this to implement an adorner that works only on object methods.

High-level #1-property properties

Do not understand why the word attribute has a property and Attribute two translations, but in Python there is a difference between the two. The latter refers to the real object property, which is the member that is saved in the obj.__dict__ (I generally prefer to use vars (obj) to fetch the dictionary), whereas the former refers to the "Method Properties" in C # or the Getter in Java, The overloaded property of the Setter method.

 class spam (object):  @property def egg (self ): return  "Some-value"  @egg. Setter def egg (self): self. _egg =  "value = %s" % valuespam = spam ()     

It's also clear that Spam.egg returns the return value of the first egg method call, Spam.egg = "abc" calls the egg for the second egg method (self=spam, Valu E= "abc") . You can also continue to define overloads for the Delete property operation. This is much easier to see than the object method, and the property is a descriptor.

High-level #n-Unrestricted user custom descriptors

In addition to these descriptor usages built into the language, there are many user-defined descriptor usages. These usages make it a useful meta-programming tool for developers to extend object behavior with greater flexibility. The descriptor's overloaded granularity is very fine compared to the overload of the primitive class for the entire class behavior, and it focuses on only one property. So we can also use the meta-class to reduce more scruples, because we can easily see its energy release boundary.

Examples of user-defined descriptors, I think the most classic is SQLAlchemy (of course, the Django Model definition is also the same). The Column class of SQLAlchemy is the creator of the descriptor. When defining a model object, write out the properties of the data table that the model corresponds to in declarative style:

ClassUser(Jsonizable,Loweridmixin,db. Model): email = db. Column (db. String (64unique= truenullable=false ) nickname = db. Column (db. Unicode (20        

The email , nickname Descriptor will host all future instances of User , with access to both properties of the same name. SQLAlchemy when mapping object relationships, you can use this feature to implement many features, such as lazy loading-until you access user.roles , execute SQL statements to query the role table and construct role The object set is returned.

Python Descriptor (Descriptor) Miscellaneous

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.