Introduction to Python Descriptor (descriptor) _python

Source: Internet
Author: User

For a long time did not write flask code related, think also really ashamed, and eggs, this time or not write flask related, don't want to hit me ah (so cheap, have the ability to bite me ah

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

The first recognition descriptor

The old rules, Talk is cheap,show me the code. Let's look at a piece of code first.

Classperson (object): "" "" "

#----------------------------------------------------------------------
def__init__ (self, first_name, last_name): "" "
Constructor" ""
 self.first_name = first_name
 Self.last_name = last_name

#----------------------------------------------------------------------
 @ Property
Deffull_name (self): "' Return ' full Name '"
' return
'%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 section of the generation must be very familiar with, well, property, who do not know, but the implementation of the property of the mechanism everyone clear? What's not clear? Then learn a furry Python ... Take a joke, let's 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 = Fdel IFDOCISNONEANDFGE Tisnotnone:doc = fget.__doc__ self.__doc__ = Doc def__get__ (self, obj, objtype=none): Ifobjisnone:returnself ifself.f
Getisnone: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 doesn't look very complicated, it's okay, let's look at it step-by-step. But here we first give a conclusion: descriptors is a special object, this kind of object realizes __get__, __set__, __delete__ these three special methods.

Detailed 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

#----------------------------------------------------------------------
 @ Property
Deffull_name (self): "' Return ' full Name '"
' return
'%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 of all, if you don't know the adorner, you might want to look at this article, in short, before we run the code, our interpreter will scan our code and replace the part that involves the adorner. Class adorners are similarly. In the preceding section, the code

@Property
Deffull_name (self): "" Return to the full name ""
 "return
"%s%s "% (Self.first_name, Self.last_name)

Triggers such a process, namely Full_name=property (Full_name). And then after we instantiate the object we call Person.full_name such a process is actually equivalent to person.full_name.__get__ (person) and then triggers the return that is written in the __get__ () method. Self.fget (obj) is the execution code within the Def full_name that we have written.

At this time, the comrades can think about the next getter (), setter (), and deleter () specific operating mechanism. = If there is still a problem, welcome to discuss it in the comments.

About descriptors

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

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

Using descriptors

First, look at the next piece of code

ClassA (object): #注: In the Python 3.x version, the use of the new class does not require an explicit designation to inherit from the object class, and if the Python 2.X (x>2) version requires

Defa (self):
pass
if__name__== "__main__":
 a=a ()
 a.a ()

Everyone notices that we have such a statement a.a (), OK, now please think about what happens when we call this method.

Ok? Have you figured it out yet? No? All right, let's go.

The first time we call a property, whether it's a member or a method, we all trigger a method that invokes the property __getattribute__ (), in our __getattribute__ () method, If we attempt to invoke a property that implements our descriptor protocol, then a call procedure type (a) is generated. __dict__[' A '].__get__ (B,type (b)). Okay, here's another conclusion: "In such a call, there is a order of precedence, and if we try to invoke a property that is a data descriptors, then regardless of whether this attribute exists in the __dict__ dictionary of our instance, the precedence call to our description of the character __get__ method, if we attempt to invoke a property that is a non data descriptors, then we first call the attributes of the existence in the __dict__ of our instance, and if they do not exist, look up our class in accordance with the corresponding principle, __dict__ in the parent class. , and once the property exists, the __get__ method is called, and the __getattr__ () method is invoked if it does not exist. A little abstract to understand? It's okay, we'll talk about it right away, but here, let's explain the data descriptors and non data descriptors, and look at an example. What is data descriptors and non data descriptors? In fact, it is very simple, in the descriptor at the same time the __get__ and __set__ protocol descriptor is the data descriptors, if only the implementation of the __GET__ protocol is non data descriptors. Okay, let's take a look at an example:

Importmath
classlazyproperty:
def__init__ (Self, func):
 Self.func = func def__get__

(self, instance, Owner):
ifinstanceisnone:
returnself
Else:
 value = Self.func (instance)
 SetAttr (instance, self.func.__name__, value)
returnvalue
classcircle:
def__init__ (Self, RADIUS):
 Self.radius = Radius
pass

 @lazyproperty
Defarea (self):
 print ("Com")
Returnmath.pi * Self.radius *2

deftest (self):
pass
if__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've already said, we're not repeating. Then, on our first call to C.area, we first query for the presence of an area descriptor in the __dict__ of instance C, and then find that there is neither a descriptor nor such a property in C, and then we query the __dict__ in Circle and look up To the attribute named area, and this is a non data descriptors, because our instance dictionary does not have a region attribute, then we call the __get__ method of the In-Class dictionary and call SetAttr in the __get__ method. Method registers the property area for an instance dictionary. Then, when we call C.area, 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 instance's Dictionary Gets the property value directly.

Use of descriptors

Descriptors are widely used, but the main purpose is to make our invocation process manageable. So we use descriptors when we need to have fine-grained control over our calling processes, like the example we mentioned earlier.

Classlazyproperty:
def__init__ (Self, func):
 Self.func = func def__get__

(self, instance, owner):
Ifinstanceisnone:
returnself
Else:
 value = Self.func (instance)
 SetAttr (instance, self.func.__name __, value)
returnvalue

def__set__ (self, instance, value=0):
pass


importmath


classcircle:
def__init__ (Self, RADIUS):
 Self.radius = Radius
pass

 @lazyproperty
defarea (self, value=0 ):
 print ("Com")
ifvalue ==0andself.radius ==0:
raisetypeerror ("Something went wring")

Returnmath.pi * Value *2ifvalue!=0elsemath.pi * Self.radius *2 deftest

(self):
Pass

Using the descriptor's characteristics to implement lazy loading, and then, 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 = Fdel Ifdocisnoneandfgetisnotnone:doc = Fget.__doc __ self.__doc__ = Doc def__get__ (self, obj, objtype=none): Ifobjisnone:returnself Ifself.fgetisNone:raiseAttributeErro R ("unreadable attribute") returnself.fget (obj) def__set__ (self, obj, Value=none): Ifvalueisnone:raisetypeerror ("You Can ' t to set value as None ') ifself.fsetisNone:raiseAttributeError ("Can ' t set attribute") Self.fset (obj, value) def__de lete__ (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__) class Test (): def__init__ (Self, value): Self.valUE = value @Property defvalue (self): Returnself.value @Value. Setter Deftest (self, x): Self.value = x

 

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

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.