Descriptions of classes and objects in Python _python

Source: Internet
Author: User

Descriptors (descriptors) are a profound but important part of the Python language. They are widely used in the Python language kernel, and mastering the descriptor will add an extra skill to the Python Programmer's Toolbox. To pave the way for the next discussion of descriptors, I'll describe some of the scenarios that programmers might encounter in their day-to-day programming activities, and then I'll explain what the descriptors are and how they can provide elegant solutions to these scenarios. In this summary, I'll use the new style class to refer to the Python version.

1. Suppose that in a program, we need to perform a rigorous type check on an object attribute. However, Python is a dynamic language, so it does not support type checking, but it does not prevent us from implementing our own version and the more elementary type checking. The traditional method of checking object property types may be in the following ways:

def __init__ (self, Name, age):
 if Isinstance (str, name):
 self.name = name
 else:
 raise TypeError ("must Be a string ")
 if isinstance (int, age):
 Self.age = age
 Else:
 raise TypeError (" must is an int ")

The above is a way to perform this type of check, but it becomes cumbersome when the number of parameters increases. In addition, before assigning a value, we can create a Type_check (type, val) function called in __init__, but how do we do this simply when we want to set the property value elsewhere? One quick solution I've come up with is getters and setters in Java, but it's not in Python style, and it's rather cumbersome.

2. Suppose in a program, we want to create some properties that are initialized immediately and then become read-only at run time. Some people can think of using the special method in Python, but the implementation is still clumsy and tedious.

3. Finally, imagine a program in which we want to customize access to object properties in some way. For example, you need to log access to this property. Again, a workaround can be thought of, even if the solution may be cumbersome and not reusable.

All of these issues are related to attribute references and are all linked together. Next, we will try to customize the access method for the property.
Python descriptor

For the issues listed above, descriptors provide elegant, concise, robust, and reusable solutions. In short, a descriptor is an object that represents the value of a property. This means that if an account object has an attribute "name", then the descriptor is another object that can be used to hold the value on behalf of the attribute "name". Special methods of "Defining __get__", "__set__", or "__delete__" in descriptor protocols, which are objects that implement one or more of these methods. The signatures for each of these methods are as follows:

Python descr.get (self,obj,type=none)->value.
 
descr.__set__ (self, obj, value)--> none
 
descr.__delete__ (self, obj)--> None

The object that implements the __get__ method is a non data descriptor, meaning that they can only be read after initialization. The object that implements __get__ and __set__ at the same time is the data descriptor, which means that the attribute is writable.

To better understand the descriptor, we give a descriptor based approach to the above problem. Using the Python descriptor to implement type checking of object properties is a very simple task. The code that the adorner implements this type of check is as follows:

 class Typedproperty (object): Def __init__ (self, name, type, default=none): Self.name = "_" + name Self.type = Type Self.default = Default if default else type () def __get__ (self, instance, CLS): Return GetAttr (instance, Self.name, Self.default) def __set__ (self,instance,value): If not isinstance (value,self.type): Rais E TypeError ("must be a%s"% Self.type) SetAttr (instance,self.name,value) def __delete__ (self,instance): Raise Attrib Uteerror ("Can ' t delete attribute") class Foo (object): Name = Typedproperty ("name", str) num = typedproperty ("num", int,4  2) >> acct = Foo () >> acct.name = "Obi" >> acct.num = 1234 >> print acct.num 1234 >> Print Acct.name Obi # Trying to assign a string to number fails >> acct.num = ' 1234 ' typeerror:must is a <type ' int ' &

Gt 

In this example, we implement a descriptor typedproperty, and this descriptor class performs type checking on any property of the class it represents. It is important to note that descriptors can only be legally defined at the class level, not at the instance level. For example, in the __init__ method in the example above.

When you access any of the properties of the class Foo instance, the descriptor invokes its __get__ method. It should be noted that the first parameter of the __get__ method is the source object to which the descriptor represents the property being referenced. When an attribute is assigned, the descriptor invokes its __set__ method. To understand why a descriptor can be used to represent an object property, we need to understand how property reference resolution in Python executes. For objects, the attribute resolution mechanism is in object.__getattribute__ (). This method converts b.x to type (b). __dict__[' x '].__get__ (b, type (b)). The parsing mechanism then uses the priority chain to search for attributes, in the priority chain, the data descriptor found in the class dictionary has precedence over the instance variable, the instance variable priority is higher than the non data descriptor, and if GetAttr () is provided, the priority chain assigns the lowest priority to GetAttr (). For a given object class, you can override the priority chain by customizing the __getattribute__ method.

After a deep understanding of the priority chain, it is easy to come up with elegant solutions for the second and third issues presented earlier. That is, using a descriptor to implement a read-only property will become a simple case of implementing a data descriptor, a descriptor without a __set__ method. Although not important in this case, the question of how to define access only requires adding the required functionality to the __get__ and __set__ methods.
Class properties

Each time we want to use descriptors, we have to define descriptor classes, which looks tedious. The Python feature provides a neat way to add a data descriptor to a property. A property signature looks like this:

Property (Fget=none, Fset=none, Fdel=none, doc=none)-> attribute

Fget, Fset, and Fdel are the getter, setter, and deleter methods of the class respectively. We use one of the following examples to illustrate how to create a property:

Class Accout (object):
 def __init__ (self):
 self._acct_num = None
 
 def get_acct_num (self): return
 self. _acct_num
 
 def set_acct_num (self, value):
 self._acct_num = value
 
 def del_acct_num (self):
 del self._ Acct_num
 
 Acct_num = Property (Get_acct_num, Set_acct_num, Del_acct_num, "account number.")

If Acct is an instance of account, Acct.acct_num will invoke Getter,acct.acct_num = value to invoke Setter,del Acct_num.acct_num will invoke deleter.

In Python, property objects and features can be implemented using descriptor protocols as described in the Descriptor Guide, as follows:

 Class Property (object): "Emulate Pyproperty_type () in objects/descrobject.c" Def __ini T__ (self, fget=none, Fset=none, Fdel=none, doc=none): Self.fget = fget Self.fset = Fset Self.fdel = Fdel if Doc is Non
 E and Fget is isn't none:doc = fget.__doc__ self.__doc__ = Doc def __get__ (self, obj, objtype=none): If obj is None: Return self if self.fget are none:raise attributeerror ("unreadable attribute") return Self.fget (obj) def __set__ (SE LF, obj, value): If Self.fset is None:raise attributeerror ("can ' t set attribute") Self.fset (obj, value) def __delet  e__ (self, obj): If Self.fdel is None:raise attributeerror ("can ' t delete attribute") Self.fdel (obj) def getter (self, Fget): return type (self) (fget, Self.fset, Self.fdel, self.__doc__) def setters (self, fset): return type (self) (SELF.FG ET, Fset, Self.fdel, self.__doc__) def deleter (self, Fdel): return type (self) (self.fget, Self.fset, Fdel, self.__doc__ )

Python also provides the @ property adorner, which you can use to create read-only properties. An attribute object has getter, setter, and deleter adorner methods that can be used to create a copy of the property through the corresponding accessor function of the decorated function. The following example best explains this:

Class C (object):
 def __init__ (self):
 self._x = None
 
 @property
 # The X property. The decorator creates a re Ad-only Property
 def x (self): return
 self._x
 
 @x.setter
 # The X property setter makes the property Writeab Le
 def x (self, value):
 self._x = value
 
 @x.deleter
 def x (self):
 del self._x

If we want the attribute to be read-only, then we can remove the setter method.

In the Python language, descriptors are widely used. Python functions, class methods, and static methods are examples of non-data descriptors. For the enumeration of how Python objects are implemented using descriptors, the Descriptor Guide gives a basic description.

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.