日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

流畅python学习笔记:第十九章:动态属性和特性

發布時間:2023/12/8 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 流畅python学习笔记:第十九章:动态属性和特性 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先來看一個json文件的讀取。書中給出了一個json樣例。該json文件有700多K,數據量充足,適合本章的例子。文件的具體內容可以在http://www.oreilly.com/pub/sc/osconfeed上查看。首先先下載數據生成json文件。

def load():
url='http://www.oreilly.com/pub/sc/osconfeed'
JSON="osconfeed.json"
if not
os.path.exists(JSON):
remote=urlopen(url)
with open(JSON,'wb') as local:
local.write(remote.read())
with open(JSON) as fp:
return json.load(fp) 我們要訪問json數據里面的例子,該如何訪問呢,一般情況是 print feed['Schedule']['speakers'][-1]['name'] 但是這種句法有個缺點,就是很冗長。能不能按照feed.Schedule.speakers[-1].name這種比較簡潔的方式來訪問呢。要實現這種訪問。需要對數據做下重新處理。這里要用到__getattr__方法:代碼如下: class FrozenJSON:
def __init__(self,mapping):
self.__data=dict(mapping)?? (1)
def __getattr__(self,name):
if hasattr(self.__data,name):
return getattr(self.__data,name)?? (2)
else:
return FrozenJSON.build(self.__data[name])? (3)
@classmethod
def build(cls,obj):
if isinstance(obj,dict):????? (4)
return cls(obj)
elif isinstance(obj,list):????? (5)
return [cls.build(item) for item in obj]
else:????????????????? (6)
return obj ? (1)構造一個字典,這樣做確保傳入的是字典 (2)確保沒有此屬性的時候調用__getattr__ (3)如果name是__data的屬性,則返回那個屬性。 (4)如果判定是字典,則返回該字典對象 (5)如果是列表,則將列表的每個元素遞歸的傳給build方法,構建一個列表 (6)如果既不是列表也不是字典,則直接返回元素 這樣實現我們就能按照前面的預期來訪問元素了:raw_feed.Schedule.speakers[-1].name

?

?

使用__new__方法來創建對象

首先來介紹下__new__方法。我們通常都將__init__稱為構造函數。其實在python中真正的構造函數應該是__new__。我們沒有具體的去實現__new__方法。是因為從object類繼承的實現已經足夠了。來看一個例子:

?

class A(object):
def __init__(self):
print '__init__'
def
__new__(cls, *args, **kwargs):
print '__new__'
print
cls
return object.__new__(cls, *args, **kwargs) if __name__=="__main__":
a=A()

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

__new__

<class '__main__.A'>

__init__

從結果可以看到首先是進入__new__,然后來生成一個對象的實例并返回。最后才是執行__init__。從這個例子可以看出在構造一個對象實例的時候,首先是進入__new__生成對象實例,然后再調用__init__方法進行初始賦值。那么我們用__new__方法來改造前面的FrozenJSON類。在前面的FrozenJSON實現中,build函數其實是不停的在遞歸各個字典對象,在遞歸過程中生成FronzenJSON實例進行處理。也就是第四步中的return cls(obj)。這里我們可以__new__來改造。
class FrozenJSON1(object):
def __new__(cls, args):
if isinstance(args,dict):
return object.__new__(cls)
elif isinstance(args,list):
return [cls(item) for item in arg]
else:
return args
def __init__(self,mapping):
self.__data=dict(mapping)
def __getattr__(self,name):
if hasattr(self.__data,name):
return getattr(self.__data,name)
else:
return FrozenJSON(self.__data[name]) 上面代碼部分中的__new__就是實現了build方法。在__getattr__中沒有找到對應name屬性時候,return FrozenJSON(self.__data[name])新建一個FrozenJSON對象進行往下遞歸

?

使用特性驗證屬性:

首先來看一個電商應用

class LineItem(object):
def __init__(self,description,weight,price):
self.description=description
self.weight=weight
self.price=price
def subtotal(self):
return self.weight*self.price


if __name__=="__main__":
raisins=LineItem('Golden raisins',10,6.95)
print raisins.subtotal()

目前這個實現都是正常的,客戶輸入要的貨物數量,和單價。在這里計算出總價。但是如果客戶一個不小心,把貨物數量設置成了負數,后果會怎樣?

if __name__=="__main__":
raisins=LineItem('Golden raisins',10,6.95)
print raisins.subtotal()
raisins.weight=-20
print raisins.subtotal()

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

69.5

-139.0

這個時候變成了給顧客錢。是不是很囧。一般來說這種情況下都會想到將變量設置為私有變量。然后則設置值的時候進行保護。

class LineItem(object):
def __init__(self,description,weight,price):
self.description=description
self.__weight=weight
self.__price=price
def set_value(self,new_value):
if new_value <=0:
raise ValueError('value must be > 0')
else:
self.__weight=new_value
def subtotal(self):
return self.__weight*self.__price

if __name__=="__main__":
raisins=LineItem('Golden raisins',10,6.95)
print raisins.subtotal()
raisins.set_value(0)

數量和價格都被設置成了私有變量。要想設置值必須通過set_value的方式。而在set_value的時候設置了保護,當設置的值小于等于0的時候,彈出異常。

Traceback (most recent call last):

? File "E:/py_prj/fluent_python/chapter19.py", line 76, in <module>

??? raisins.set_value(0)

? File "E:/py_prj/fluent_python/chapter19.py", line 68, in set_value

??? raise ValueError('value must be > 0')

ValueError: value must be > 0

對于這種情況,我們還有另外一種方法。那就是將屬性變成一種特性。采用property方法。代碼如下:

class LineItem(object):
def __init__(self,description,weight,price):
self.description=description
self.weight=weight
self.price=price
def subtotal(self):
return self.weight*self.price
@property
def weight(self):
return self.__weight
@weight.setter
def weight(self,value):
if value <=0:
raise ValueError('value must be > 0')
else:
self.__weight=value

if __name__=="__main__":
raisins=LineItem('Golden raisins',10,6.95)
print raisins.subtotal()
raisins.weight=0

通過@property將weight變成一個特性,@weight.setter來進行賦值。雖然內置的property經常用作裝飾器,但它其實是個類。代碼可以改寫成下面的樣子:

class LineItem(object):
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:
raise ValueError('value must be? > 0')
else:
self.__weight=value
weight=property(get_weight,set_weight)

至于用哪種方法更好,這個屬于見仁見智的看法。我個人覺得用裝飾器的方式看起來更簡潔一些。因為可以很明白的看出賦值和讀值,而不用按照慣例在方法名的前面加上get和set

?

接下來看下屬性和特性的差別:

class Class(object):
data='the class data attr'
@property
def prop(self):
return 'the prop value'


if
__name__=="__main__":
obj=Class()
print vars(obj)???? (1)
print obj.data????? (2)
obj.data='bar'
print
vars(obj)???? (3)
print obj.data????? (4)
print Class.data??? (5) (1)??? vars函數返回的是obj的__dict__函數,沒有實例屬性 (2)??? 讀取obj.data實際上讀取的是Class.data的值 (3)??? 為obj.data賦值后,創建一個實例屬性。 (4)??? 讀取obj.data,獲取的是實例屬性的值。實例屬性會覆蓋類屬性data (5)??? 類屬性還是以前的樣子,并沒有被覆蓋 ? 下面來看下特性的例子 if __name__=="__main__":
obj=Class()
print Class.prop????? (1)
print obj.prop?? ?????(2)
obj.__dict__['prop']='foo'???? (3)
print
vars(obj)
print obj.prop????????????????? (4)
Class.prop='baz'???????????????
print
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)??? 直接從Class中讀取prop特性。獲取的是特性本身 (2)??? 讀取obj.prop (3)??? 通過__dict__方法來給實例增加一個屬性 (4)??? 此時實例有2個實例屬性,data和prop, 但是在調用prop的時候仍然是讀取特性的方法,而不是實例屬性。表明特性沒有被實例屬性覆蓋 (5)??? 當類的prop特性被覆蓋后,銷毀該特性對象。再次讀取obj.prop的時候,Class.prop不再是特性了,因此不會覆蓋obj.prop。 ? 總結:從這里可以看出,當讀取實例屬性的時候會覆蓋類的屬性。而在讀取實例特性的時候,特性不會被實例屬性覆蓋,而依然是讀取類的特性。除非類特性被銷毀。

轉載于:https://www.cnblogs.com/zhanghongfeng/p/7468881.html

總結

以上是生活随笔為你收集整理的流畅python学习笔记:第十九章:动态属性和特性的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。