摘要:更多描述可見文檔這種惰性求值的方法在很多模塊中都會使用,比如中的使用上與例子一致,如表單中的討論在大部分情況下,讓屬性具有惰性求值能力的全部意義就在于提升程序性能。當(dāng)不需要這個屬性時就能避免進行無意義的計算,同時又能阻止該屬性重復(fù)進行計算。
起步
我們希望將一個只讀的屬性定義為 property 屬性方法,只有在訪問它時才進行計算,但是,又希望把計算出的值緩存起來,不要每次訪問它時都重新計算。
解決方案定義一個惰性屬性最有效的方法就是利用描述符類來完成它,示例如下:
class lazyproperty: def __init__(self, fun): self.fun = fun def __get__(self, instance, owner): if instance is None: return self value = self.fun(instance) setattr(instance, self.fun.__name__, value) return value
要使用這個工具,可以像下面的方式來使用它:
class Circle: def __init__(self, radius): self.radius = radius @lazyproperty def area(self): print("Computing area") return 3.1415 * self.radius ** 2 c = Circle(5) print(c.area) print(c.area)
可以看出,這里的實例方法 area() 只會被調(diào)用一次。
為什么會這樣如果類中定義了 __get__()、__set__() 、__delete__() 中的任何方法,那么這個就被成為描述符(descriptor)。
一般情況下(我是說一般情況下),訪問屬性的默認行為是從對象的字典中獲取,并沿著一個查找鏈的順序進行搜索,比如對于 a.x 有一個查找鏈,從 a.__dict__["x"] 然后是 type(a).__dict__["x"],再繼續(xù)通過 type(a) 的基類開始。
而如果查找的值是一個描述符對象,則會覆蓋這個默認的搜索行為,優(yōu)先采用描述符的行為,這個行為會因為如果調(diào)用而有些不同。這里就只說明例子中的情況。
如果描述符綁定的對象實例,a.x 則轉(zhuǎn)換為調(diào)用: type(a).__dict__["x"].__get__(a, type(a))。
當(dāng)一個描述符之定義 __get__() 方法,則它的綁定關(guān)系比一般情況下要弱化很多。特別是,只有當(dāng)被訪問的屬性不存在對象字典中時,__get__() 才會被調(diào)用。
更多描述可見文檔:https://docs.python.org/3/ref...
這種惰性求值的方法在很多模塊中都會使用,比如django中的 cached_property:
使用上與例子一致,如表單中的 changed_data :
討論在大部分情況下,讓屬性具有惰性求值能力的全部意義就在于提升程序性能。當(dāng)不需要這個屬性時就能避免進行無意義的計算,同時又能阻止該屬性重復(fù)進行計算。
本文的技巧中有一個潛在的缺點,就是計算出的值后就變成可變的(mutable)。
>>> c.area 78.53 >>> c.area = 3 >>> c.area 3
如果考慮可變性的問題,可以使用另一種實現(xiàn)方式,但執(zhí)行效率會稍打折扣:
def lazyproperty(func): name = "_lazy_" + func.__name__ @property def lazy(self): if hasattr(self, name): return getattr(self, name) value = func(self) setattr(self, name, value) return value return lazy
如果使用這種方式,就會發(fā)現(xiàn) set 操作是不允許的,所有的 get 操作都必須經(jīng)由屬性的 getter 函數(shù)來處理,這比直接在實例字典中查找相應(yīng)的值要慢一些。
參考https://docs.python.org/3/ref...
《Python Cookbook 第三版》
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/42231.html
摘要:官方也宣布在停止對的維護。并且在很多面試過程中,面試官都會問與的區(qū)別。的版本,常被稱為,或簡稱。與部分地支持這種形式的語法。捕獲異常的語法由改為。在中,表示八進制字面量的方式只有一種,就是。已經(jīng)支援新的模組。 前言 如果你是剛接觸 Python 的初學(xué)者,那你可能是直接學(xué)習(xí) Python 3.x 版本。對于 Python 2.x 的版本是不會有所接觸。官方也宣布在 2020 停止對 P...
摘要:純函數(shù)式狀態(tài)隨機數(shù)生成器很明顯,原有的函數(shù)不是引用透明的,這意味著它難以被測試組合并行化。售貨機在輸出糖果時忽略所有輸入本章知識點惰性求值函數(shù)式狀態(tài) 第二節(jié)?惰性求值與函數(shù)式狀態(tài) 在下面的代碼中我們對List數(shù)據(jù)進行了一些處理 List(1,2,3,4).map(_ + 10).filter(_ % 2 == 0).map(_ * 3) 考慮一下這段程序是如何求值的,如果我們跟蹤一下...
摘要:聲明式編程一種編程范式,與命令式編程相對立。常見的聲明式編程語言有數(shù)據(jù)庫查詢語言,正則表達式邏輯編程函數(shù)式編程組態(tài)管理系統(tǒng)等。函數(shù)式編程,特別是純函數(shù)式編程,嘗試最小化狀態(tài)帶來的副作用,因此被認為是聲明式的。 編程范式與函數(shù)式編程 一、編程范式的分類 常見的編程范式有:函數(shù)式編程、程序編程、面向?qū)ο缶幊?、指令式編程等。在面向?qū)ο缶幊痰氖澜?,程序是一系列相互作用(方法)的對象(Class...
摘要:同時還定義了接口,使得其下級可以從這里得到一個迭代器,對于該進行遍歷。迭代器在中也是一個約定的協(xié)議,實現(xiàn)該協(xié)議的對象要支持和兩個接口方法。從迭代器的邏輯中,可以看到,當(dāng)對象作為其他的上級時,如果實現(xiàn)上傳下達。 背景:惰性求值? 來看一個 lazy.js 主頁提供的示例: var people = getBigArrayOfPeople(); var results = _.chain(...
摘要:初始化和配置對象關(guān)系映射。的則需要在中聲明。例如配置信息中指出是可以綁定多個數(shù)據(jù)庫引擎。是通過解決一對多的關(guān)系。將會返回學(xué)院學(xué)生人數(shù)將會返回學(xué)生的學(xué)院信息的類實例。處理關(guān)系對象查詢中有詳細的說明。 初始化和配置 ORM(Object Relational Mapper) 對象關(guān)系映射。指將面對對象得方法映射到數(shù)據(jù)庫中的關(guān)系對象中。Flask-SQLAlchemy是一個Flask擴展,能...
閱讀 527·2021-10-09 09:57
閱讀 548·2019-08-29 18:39
閱讀 881·2019-08-29 12:27
閱讀 3086·2019-08-26 11:38
閱讀 2738·2019-08-26 11:37
閱讀 1345·2019-08-26 10:59
閱讀 1435·2019-08-26 10:58
閱讀 1037·2019-08-26 10:48