Getting Started with Python descriptors (descriptor)

Source: Internet
Author: User
For a long time did not write Flask code related, think also really ashamed, but and eggs, this time or not write Flask related, do not defy you to hit me ah (so cheap, have the ability to bite me ah

This time I'll write a very important thing about Python, the descriptor (descriptor)

Initial Knowledge Descriptor

The usual, talk is cheap,show me the code. Let's take a look at some code.

Classperson (object): "" "" "" #----------------------------------------------------------------------def__init__ ( Self, first_name, last_name): "" "Constructor" "" Self.first_name = first_name self.last_name = last_name#--------------- -------------------------------------------------------@propertydeffull_name: "" "Return The Full Name" " Return "%s%s"% (Self.first_name, self.last_name) if__name__== "__main__": Person = person ("Mike", "Driscoll") print ( Person.full_name) # ' Mike Driscoll ' Print (person.first_name) # ' Mike '

This period of people are certainly very familiar with, well, property, who do not know, but the property of the implementation mechanism are you clear? What's not clear? That's a furry Python. For a joke, let's take a look at the following code

Classproperty (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 = Fdelifdocisnoneandfgetisnotnone:doc = fget.__doc__ SE lf.__doc__ = docdef__get__ (self, obj, Objtype=none): IfobjisNone:returnselfifself.fgetisNone:raiseAttributeError (" Unreadable attribute ") returnself.fget (obj) def__set__ (self, obj, value): Ifself.fsetisNone:raiseAttributeError (" Can ' t set attribute ") Self.fset (obj, value) def__delete__ (self, obj): Ifself.fdelisNone:raiseAttributeError (" Can ' t Delete attribute ") Self.fdel (obj) defgetter (self, Fget): ReturnType (self) (fget, Self.fset, Self.fdel, self.__doc__) Defsetter (self, Fset): ReturnType (self) (self.fget, Fset, Self.fdel, self.__doc__) defdeleter (self, Fdel): ReturnType ( Self) (self.fget, Self.fset, Fdel, self.__doc__)

It seems to be not very complicated, okay, let's take a step-by-step look. But here we first give a conclusion: descriptors is a special kind of object, this kind of object realizes __get__, __set__, __delete__ these three special methods.

EXPLANATION Descriptor

Talk about property.

In the above, we give the Propery implementation code, now let's talk about this in detail

Classperson (object): "" "" "" #----------------------------------------------------------------------def__init__ ( Self, first_name, last_name): "" "Constructor" "" Self.first_name = first_name self.last_name = last_name#--------------- -------------------------------------------------------@Propertydeffull_name: "" "Return The Full Name" " Return "%s%s"% (Self.first_name, self.last_name) if__name__== "__main__": Person = person ("Mike", "Driscoll") print ( Person.full_name) # ' Mike Driscoll ' Print (person.first_name) # ' Mike '

First, if you don't know about adorners, you might want to look at this article, in short, before we formally run the code, our interpreter will scan our code and replace the part that touches the adorner. The same kind of decorator. In the preceding section, this code

@Propertydeffull_name: "" "Return the Full Name" "" Return "%s%s"% (Self.first_name, self.last_name)

Will trigger such a process, Full_name=property (full_name). Then we call Person.full_name after we instantiate the object, which is actually equivalent to person.full_name.__get__ (person) and then triggering the return written in the __get__ () method. Self.fget (obj) is the execution code in the Def Full_name that we wrote originally.

This time, the comrades can think about the getter (), setter (), and deleter () the specific operating mechanism of =. = If you still have a problem, you are welcome to discuss it in the comments.

About descriptors

Remember one of the definitions we mentioned before: descriptors is a special object that implements the __get__, __set__, __delete__ three special methods. Then in the description of the official Python document, in order to reflect the importance of the descriptor, there is a passage: "They is the mechanism behind properties, methods, static methods, class methods, and super (). They is used throughout Python itself to implement the new style classes introduced in version 2.2. "In short, there is a day, seconds, seconds of air after the first descriptor." Well, in a new class, attributes, method calls, static methods, class methods, and so on are all based on the specific use of descriptors.

OK, you might want to ask, why is the descriptor so important? Don't worry, we'll see.

Using descriptors

First, take a look at the next piece of code

ClassA (object): #注: In the Python 3.x version, the use of the new class does not need to be explicitly specified to inherit from the object class, if it is required in Python 2.X (x>2) version

Defa (self):p assif__name__== "__main__": A=a () A.A ()

We all notice that we have such a statement a.a (), OK, now let's think about what happens when we call this method.

Ok? Did you come up with that? No? All right, let's go.

First we call a property, either a member or a method, we trigger a method to invoke the property __getattribute__ (), in our __getattribute__ () method, If we try to invoke a property that implements our descriptor protocol, then a call procedure of type (a) is generated. __dict__[' A '].__get__ (B,type (b)). Okay, here's another conclusion: "In such a call process, there is a priority order, if we try to invoke the property is a data descriptors, then regardless of whether this property exists in our instance of the __dict__ dictionary, the first call we describe the character __get__ method, if we try to invoke the property is a non data descriptors, then we call the first instance of the __dict__ in the existence of the property, if not present, then according to the corresponding principle to find our class, the parent class __dict__ If the property exists, call the __get__ method, or call the __getattr__ () method if it does not exist. Is it a bit abstract to understand? OK, we'll talk about it right away, but here we have to explain the data descriptors and non data descriptors, and then look at an example. What is data descriptors and non data descriptors? In fact, it is very simple to implement both the __GET__ and __SET__ protocol descriptor in the descriptor is the data descriptors, if the __GET__ protocol is only implemented non data descriptors. Okay, let's take a look at an example:

Importmathclasslazyproperty:def__init__ (Self, func): Self.func = funcdef__get__ (self, instance, owner): IfinstanceisNone:returnselfelse:value = Self.func (instance) SetAttr (instance, self.func.__name__, value) Returnvalueclasscircle:def__init__ (Self, radius): Self.radius = Radiuspass @lazypropertydefarea (self): print ("Com") Returnmath.pi * Self.radius *2deftest (self):p assif__name__== ' __main__ ': c=circle (4) print (C.area)

OK, let's take a closer look at this code, first the class descriptor @lazyproperty replacement process, as we said before, we are not repeating. Then, when we first called C.area, we first queried if there was an area descriptor in the __dict__ of instance C, and then found that there was neither a descriptor in C nor a property, and then we queried the __dict__ in Circle and looked up To a property named area, and this is a non data descriptors, because there is no region attribute in our instance dictionary, we call the __get__ method of the area in the class dictionary and call SetAttr in the __get__ method method to register the property area for the instance dictionary. Then, when we call C.area later, we can find the presence of the area attribute in the instance dictionary, and the area in the class dictionary is a non data descriptors, so we do not trigger the __get__ method implemented in the code, but directly from the dictionary of the Instance Gets the property value directly.

The use of descriptors

Descriptors are widely used, but their main purpose is to make our invocation process controllable. So we use descriptors when we need to fine-tune our invocation process, like the example we mentioned earlier

Classlazyproperty:def__init__ (Self, func): Self.func = funcdef__get__ (self, instance, owner): Ifinstanceisnone: Returnselfelse:value = Self.func (instance) SetAttr (instance, self.func.__name__, value) returnvaluedef__set__ (self, instance, value=0):p assimportmathclasscircle:def__init__ (Self, radius): Self.radius = Radiuspass @ Lazypropertydefarea (self, value=0): Print ("Com") Ifvalue ==0andself.radius ==0:raisetypeerror ("Something went wring") Returnmath.pi * Value *2ifvalue!=0elsemath.pi * Self.radius *2deftest (self):p

Lazy loading using the descriptor's attributes, for example, we can control the value of the property assignment

Classproperty (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 = Fdelifdocisnoneandfgetisnotnone:doc = fget.__doc__ SE lf.__doc__ = docdef__get__ (self, obj, Objtype=none): IfobjisNone:returnselfifself.fgetisNone:raiseAttributeError (" Unreadable attribute ") returnself.fget (obj) def__set__ (self, obj, Value=none): Ifvalueisnone:raisetypeerror (" Can " T to set value as None ") ifself.fsetisNone:raiseAttributeError (" Can ' t set attribute ") Self.fset (obj, value) def__delete__ (self, obj): Ifself.fdelisNone:raiseAttributeError ("can ' t delete attribute") Self.fdel (obj) defgetter (self, fget): ReturnType (self) (fget, Self.fset, Self.fdel, self.__doc__) defsetter (self, Fset): ReturnType (self) (self.fget, Fset, Self.fdel, self.__doc__) defdeleter (self, Fdel): ReturnType (self) (self.fget, Self.fset, Fdel, self.__doc__) classtest ( ):d ef__init__ (self, value): Self.value = value @PropertydefValue (self): returnSelf.value @Value. Setterdeftest (self, x): Self.value = x 

As the above example illustrates, we can determine whether the value passed in is valid, and so on.

  • 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.