Fluent Python Learning notes: 19th: Dynamic properties and Features

Source: Internet
Author: User

First look at a JSON file read. A JSON example is given in the book. The JSON file has more than 700 k, and the amount of data is sufficient for the example in this chapter. The specific contents of the file can be viewed on http://www.oreilly.com/pub/sc/osconfeed. First, download the data to generate the JSON file.

Load ():
Url=' Http://www.oreilly.com/pub/sc/osconfeed '
json="Osconfeed.json"
Os.path.exists (JSON):
Remote=urlopen (URL)
Open (JSON,' WB 'Local:
Local.write (Remote.read ())
Fp:
Json.load (FP)
We want to access the JSON data inside the example, how to access it, the general situation is
feed[' Schedule '[' Speakers'][-1]['name '] but this syntax has a drawback, it is very lengthy. Can you follow the feed. Schedule.speakers[-1].name this relatively concise way to access it. To implement this access. The data needs to be re-processed. Here's how to use the __getattr__ method: The code is as follows:
classFrozenjson:
def__init__ (self,mapping):
Self.__data=dict (mapping) (1)
def__getattr__ (Self,name):
ifHasattr (Self.__data,name):
returnGetAttr (Self.__data,name) (2)
Else:
returnFrozenjson.build (Self.__data[name]) (3)
@classmethod
defBuild (Cls,obj):
ifIsinstance (obj,dict): (4)
returnCLS (obj)
elifIsinstance (obj,list): (5)
return[Cls.build (item) forIteminchObj
Else: (6)
returnObj
(1) construct a dictionary that ensures that the dictionary is passed in
(2) Ensure that the __getattr__ is not called when this attribute is not
(3) If name is a property of __data, that property is returned.
(4) If the decision is a dictionary, the Dictionary object is returned
(5) If it is a list, pass each element of the list recursively to the build method, building a list
(6) If neither the list nor the dictionary, returns the element directly
This enables us to access the elements according to the previous expectations: Raw_feed. Schedule.speakers[-1].name

Use the __new__ method to create an object

First, introduce the next __new__ method. We usually refer to __init__ as a constructor function. In fact, the real constructor in Python should be __new__. We have no specific way to implement the __new__ method. is because the implementation inherited from the object class is sufficient. Take a look at an example:

A (object):
__init__ (self):
print ' __init__ '
__new__ (CLS, *args, **kwargs):
print ' __new__ '
Cls
Object.__new__ (CLS, *args, **kwargs)
__name__=="__main__":
A=a ()

E:\python2.7.11\python.exe e:/py_prj/fluent_python/chapter19.py

__new__

<class ' __main__. A ' >

__init__

From the result you can see that the first step is to enter __new__, and then to generate an instance of an object and return it. The last is the execution __init__. From this example, we can see that when constructing an object instance, the first step is to enter __new__ to generate the object instance, and then call the __init__ method for the initial assignment. Then we use the __new__ method to transform the previous Frozenjson class. In the previous implementation of Frozenjson, the build function is in fact recursive to the various dictionary objects, in the recursive process of generating Fronzenjson instances for processing. That's the fourth step.returnCLS (obj). Here we can __new__ to transform.
classFrozenJSON1 (object):
def__new__ (CLS, args):
ifIsinstance (args,dict):
returnOBJECT.__NEW__ (CLS)
elifIsinstance (args,list):
return[CLS (item) forIteminchArg
Else:
returnArgs
def__init__ (self,mapping):
Self.__data=dict (mapping)
def__getattr__ (Self,name):
ifHasattr (Self.__data,name):
returnGetAttr (Self.__data,name)
Else:
returnFrozenjson (Self.__data[name])
The __new__ in the above Code section is the implementation of the build method. When the corresponding name attribute is not found in __getattr__, Frozenjson (Self.__data[name]) creates a new Frozenjson object to recursively

To validate attributes with attributes:

First look at an e-commerce application

LineItem (object):
__init__ (Self,description,weight,price):
Self.description=description
Self.weight=weight
Self.price=price
Subtotal (self):
Self.weight*self.price


__name__=="__main__":
Raisins=lineitem (' Golden raisins ', 10,6.95)
Raisins.subtotal ()

At present, this implementation is normal, the customer input the quantity of goods, and unit price. The total price is calculated here. But what happens if a customer accidentally sets the quantity of the goods to a negative number?

__name__=="__main__":
Raisins=lineitem (' Golden raisins ', 10,6.95)
Raisins.subtotal ()
Raisins.weight=-20
Raisins.subtotal ()

E:\python2.7.11\python.exe e:/py_prj/fluent_python/chapter19.py

69.5

-139.0

It turned out to be money for the customers. Isn't it embarrassing. In general this scenario would have the idea of setting the variable to a private variable. Then the value is set for protection.

classLineItem (object):
def__init__ (Self,description,weight,price):
Self.description=description
Self.__weight=weight
Self.__price=price
defSet_value (Self,new_value):
ifNew_value <=0:
RaiseValueError (' value must be > 0 ')
Else:
Self.__weight=new_value
defSubtotal (self):
returnSelf.__weight*self.__price

if__name__=="__main__":
Raisins=lineitem (' Golden raisins ', 10,6.95)
PrintRaisins.subtotal ()
Raisins.set_value (0)

Both the quantity and the price are set as private variables. To set the value must pass Set_value way. And when the Set_value is set to protect, when the value of the setting is less than or equal to 0, the exception pops up.

Traceback (most recent):

File "e:/py_prj/fluent_python/chapter19.py", line-in <module>

Raisins.set_value (0)

File "e:/py_prj/fluent_python/chapter19.py", line. In Set_value

Raise ValueError (' value must be > 0 ')

Valueerror:value must be > 0

We have another way of doing this. That is to turn the attribute into an attribute. Use the property method. The code is as follows:

classLineItem (object):
def__init__ (Self,description,weight,price):
Self.description=description
Self.weight=weight
Self.price=price
defSubtotal (self):
returnSelf.weight*self.price
@property
defWeight (self):
returnSelf.__weight
@weight. Setter
defWeight (Self,value):
ifValue <=0:
RaiseValueError (' value must be > 0 ')
Else:
Self.__weight=value

if__name__=="__main__":
Raisins=lineitem (' Golden raisins ', 10,6.95)
PrintRaisins.subtotal ()
Raisins.weight=0

By @property, the weight becomes an attribute, @weight. Setter to assign the value. Although the built-in property is often used as an adorner, it is actually a class. The code can be rewritten like this:

classLineItem (object):
def__init__ (Self,description,weight,price):
Self.description=description
Self.weight=weight
Self.price=price
defSubtotal (self):
returnSelf.weight*self.price
defGet_weight (self):
returnSelf.__weight
defSet_weight (Self,value):
ifValue <= 0:
RaiseValueError (' value must be > 0 ')
Else:
Self.__weight=value
Weight=property (Get_weight,set_weight)

As to which method is better, this is a matter of opinion. I personally feel that the way the adorner looks is more concise. Because you can clearly see the assignment and the read value, rather than following the Convention to precede the method name with get and set

Next look at the difference between properties and attributes:

Class (object):
Data=' The class data attr '
@property
Prop (self):
Return ' The prop value '


__name__=="__main__":
Obj=class ()
VARs (obj) (1)
Obj.data (2)
Obj.data=' Bar '

Obj.data (4)
Class.data (5)
(1) The VARs function returns the __dict__ function of obj with no instance property
(2) Read Obj.data actually read the value of Class.data
(3) After assigning a value to Obj.data, create an instance property.
(4) Read Obj.data, gets the value of the instance property. Instance properties override class properties data
(5) class attribute or previous appearance, not overwritten
Here's an example of a feature
__name__=="__main__":
Obj=class ()
Class.prop (1)

obj.__dict__[' prop ']=' foo ' (3)
VARs (obj)
Obj.prop (4)
class.prop=
Obj.prop (5)
E:\python2.7.11\python.exe e:/py_prj/fluent_python/chapter19.py
<property Object at 0x01b4f540>
The prop value
{' prop ': ' foo '}
The prop value
Foo
(1) Read the Prop property directly from the class. Gets the attribute itself
(2) Read Obj.prop
(3) Adding an attribute to an instance by using the __dict__ method
(4) The instance has 2 instance properties, data and prop, but is still the method of reading the attribute when calling prop, not the instance property. Indicates that the attribute is not overridden by an instance property
(5) When the prop attribute of the class is overwritten, the attribute object is destroyed. When reading Obj.prop again, Class.prop is no longer a feature and therefore does not overwrite obj.prop.
Summary: From here you can see that the properties of the class are overwritten when the instance properties are read. When reading instance attributes, attributes are not overwritten by instance attributes, but are still read by the class. Unless the class attribute is destroyed.

Fluent Python Learning notes: 19th: Dynamic properties and Features

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.