This article mainly introduces the detailed description of the dynamic properties and characteristics of Python, small series feel very good, and now share to everyone, but also to make a reference. Let's take a look at it with a little knitting.
Introductory remarks: This article records my key knowledge and personal experience in the meta-programming of the basics of Python, and intends to get started with the friends of Python to learn and communicate with each other.
First, using dynamic properties to process the JSON data source
Properties: In Python, the properties of the data and the methods that manipulate the data are collectively attributes.
Meta-programming: Using meta-class to program, meta-class → class → object, meta-analogy class more abstract, generate class class.
1. Using dynamic properties to access JSON class data
First edition: Review data with Json.load (FP)
From urllib.request import urlopenimport warningsimport osimport jsonurl = ' http://www.oreilly.com/pub/sc/ Osconfeed ' json = ' Data/osconfeed.json ' def load (): if not os.path.exists (JSON): msg = ' downloading {} to {} '. Format (URL, JSON) Warnings.warn (msg) #如果需要下载就发出提醒. with Urlopen (URL) as remote, open (JSON, ' WB ') as Local: #在with语句中使用两个上下文管理器分别用于读取和保存远程文件. Local.write (Remote.read ()) with Open (JSON) as FP: return Json.load (FP) # The Json.load function parses the JSON file and returns the Python native object.
Second Edition: Accessing JSON class data using dynamic properties
The first version of the deep data format is verbose, such as feed ' Schedule ' 40, we want to use the feed on the read attribute. Schedule.events[40].name This kind of way to improve. and the second version of the class can be recursive, automatically processing nested mappings and lists.
From collections Import Abcclass Fronenjson (): def __init__ (self,mapping): self.__data=dict (mapping) #创建副本, Also ensure that the dictionary is processed. def __getattr__ (self, name): #仅当没有指定名称的属性才调用__getattr__方法. if Hasattr (self,name): return GetAttr (self.__data,name) else: return Fronenjson.build (self.__ Data[name]) @classmethod def __build__ (cls,obj): if Isinstance (obj,abc. Mapping): #判断obj是否是映射. return cls (obj) #创建FrozenJSON对象. elif isinstance (obj,abc. mutablesequence): return [Cls.build (item) for item in obj] #递归调用. Build () method to build a list. else: #既不是字典也不是列表, the element itself is returned. return obj
Analysis: The key of Fronenjson class is the __getattr__ method. The interpreter calls a special __getattr__ method only if it is not possible to get the property in the usual way (that is, the specified property cannot be found in an instance, class, or superclass).
2. Handling Invalid property names
In Python, a property with the name keyword is invalid because the keyword is reserved. Therefore, the __init__ in the second edition needs to be improved:
def __init__ (self,mapping): self.__data={} for Key,value in Mapping.items (): if Keyword.iskeyword (key): key+= ' _ ' #与Python关键字重复的key在尾部加上下划线. Self.__data[key]=value
3, the use of special methods __new__
Third edition: Use the __new__ construction method to convert a class into a flexible object factory function.
From collections Import Abcclass Fronenjson (): def __new__ (CLS, arg): # __new__ is a class method, and the first argument is the class itself CLS. if Isinstance (ARG, ABC. Mapping): return Super (). __new__ (CLS) #委托给超类object基类的__new__方法处理. elif isinstance (ARG, ABC. mutablesequence): # The remaining method is consistent with the previous build method. return [CLS (item) for item in ARG] else: return arg def __init__ (self,mapping): self.__data={} For Key,value in Mapping.items (): if Keyword.iskeyword (key): key+= ' _ ' self.__data[key]=value def __getattr__ (self, name): if Hasattr (self,name): return GetAttr (self.__data,name) else: return Fronenjson (Self.__data[name])
Second, the characteristics
1. Class attributes, instance properties, private properties, and attributes
Class properties: Class properties are initialized outside of __init__ (), belong to the class, and all instances share one property.
Call Method: The Class property is called internally with the ClassName. Class property name, and can be invoked externally either with the ClassName. Class property name or by using the InstanceName. Class property name.
Instance properties: Instance properties are owned by each instance and are not interfering with each other.
Private properties:
Start with a single underline: Just tell someone that this is a private property, and the changes can still be accessed externally.
Double underline __: The outside cannot be visited or changed by Instancename.propertyname, it is actually converted to _classname__propertyname.
Attribute: is a class property that is used to manage instance properties.
Feature usage: It is often used to turn public properties into properties managed using the Read value method and the set value method, and to implement business rules without affecting client code.
Attention:
Do not use the same name for instance properties and class properties. Otherwise, the instance property obscures the Class property, and a hard-to-find error occurs.
Instance properties do not obscure class attributes, but class attributes obscure instance properties.
This is because Obj.attr does not start looking for attr from instance obj, but begins with obj.__class__, and Python looks for attr in the instance only if there is no attribute named attr in the class.
In short, class attributes > Instance Properties > Class properties for the masking hierarchy.
2. Validate attributes with attributes
You can use attributes to verify the validity of instance properties, and to adjust other properties based on the relationship between known attributes and attributes to avoid hard coding.
Case: If a store operates a variety of organic foods such as nuts and grains, each customer's order will contain a range of items in the store, and we will need to calculate the total price according to the customer's order.
Analysis: We do not want the product weight of customer orders to be non-positive, you need to use the @property adorner to achieve the value of the acquisition and set, to verify the validity of the instance properties. The code is as follows:
Class LineItem (): def __init__ (self,description,weight,price): self.description=description Self.weight=weight self.price=price def subtotal (self): return self.weight*self.price @property # Read value. def weight (self): return self.__weight# The True value is stored in the private property. @weight. Setter def weight (self,value): if value >0: self.__weight=value# Valid value is stored in the private attribute. else: raise ValueError (' Value must be > 0 ') #对于无效的值抛出ValueError.
Tips: When we need to set read-only properties, use only @property, without using @func.setter.
Principle Analysis: In order to better understand the principle of @property decorator, we write a version of the same effect but did not use the adorner code.
Class LineItem: def __init__ (self, description, weight, price): self.description = Description Self.weight = weight Self.price = Price def subtotal (self): return self.weight * self.price def get_ Weight (self): #普通读值方法. return self.__weight def set_weight (self, value): #普通设值方法. if value > 0: self.__weight = value else: raise ValueError (' value must be > 0 ') weight = pr Operty (Get_weight, Set_weight) #构建property对象, assigns to the exposed class attribute.
The full signature of the property construction method:
Property (Fget=none, Fset=none, Fdel=none, Doc=none)
3. Characteristic factory function
There are two ways to define attributes abstractly, one is to use the attribute factory function, and the other is to use the descriptor class.
Here we use the attribute factory function to complete the order settlement cases mentioned above:
Def quantity (Storage_name): def qty_getter (instance): # instance refers to the LineItem instance where the attribute is to be stored. return Instance.__dict__[storage_name] # refers to the free variable storage_name in the closure, and the value is obtained directly from the instance.__dict__ in order to skip the attribute and prevent infinite recursion. def qty_setter (instance, value): if value > 0: instance.__dict__[storage_name] = value # Same as store, skip attribute. else: raise ValueError (' value must is > 0 ') return property (Qty_getter, Qty_setter) # Builds and returns the custom attribute object. Class LineItem: weight = quantity (' weight ') # defines the custom attribute weight as a class property. Price = Quantity (' price ') # ibid. def __init__ (self, description, weight, price): self.description = description self.weight = weight # Here the attribute is activated to verify the validity of the value. Self.price = Price def subtotal (self): return self.weight * Self.price # This takes advantage of the attribute to get the value stored in the instance.
4. Delete attributes using attributes
Class Blackknight:def __init__ (self): self.members = [' An arm ', ' another arm ', ' a leg ', ' another leg ' . phrases = ["' Tis but a scratch.", "It's just a flesh wound.", "I ' m invincible!", "All right , we'll call it a D Raw. "] @property def member (self): print (' Next member are: ') return self.members[0] @member. Deleter def member (self): C8/>text = ' BLACK KNIGHT (loses {}) \n--{} ' print (Text.format (self.members.pop (0), Self.phrases.pop (0)))
To delete an attribute simply issue an instruction in the main program: Del obj.attr
Iii. important properties and functions for handling attributes
1. Special attributes
__CLASS__: The reference to the class to which the object belongs (that is, obj.__class__ and type (obj) are the same). Some special methods in Python, such as __getattr__, are found only in the object's class, not in the instance.
__DICT__: A mapping that stores the writable properties of an object or class.
__SLOTS__: A class can define this property to limit what properties the instance has.
2. Built-in functions
Dir ([Object]): Lists most of the properties of an object.
GetAttr (Object,name[,default]): Gets the corresponding property of the name string from the object. The obtained property may come from the class or superclass to which the object belongs.
Hasattr (Object,name): Returns True if the specified property exists in the object, or if it can be obtained in some way (such as inheritance) through the object property.
SetAttr (Object,name,value): Sets the value of the object object's specified property to value, provided that the object can accept that value. This function may create a new property, or overwrite an existing one.
VAR ([object]): Returns the __dict__ property of the object.
3. Special methods
-
__delattr__ (self,name): This method is called whenever a property is deleted using the DEL statement.
-
__dir__ (self): Called when the object is passed to the Dir function, listing properties.
-
__getattr__ (self,name): Called after the Obj,class and superclass have been searched only if the specified property has failed.
-
__getattribute__ (self,name): This method is always called when trying to get the specified property. Except when looking for properties that are special attributes or special methods. To prevent infinite recursion, the implementation of the __GETATTRIBUTE__ method uses Super (). __getattribute__ (Obj,name).
-
__setattr__ (Self,name,value): This method is always called when attempting to set the specified property. The dot number and setattr built-in function
-
Trigger this method.