Python中l(wèi)azy property的兩種方法小結(jié)
我們都知道,在Python的類中,__dict__
保存了一個對象所有的屬性,如下面的例子,我們建立了一個Circle的對象,對象的字典中保存著半徑radius 這個k-v值:
class Circle(object): def __init__(self,radius): self.radius = radius c = Circle(2.5) print(c.__dict__) #{'radius': 2.5}
對于類中的方法,我們有時候希望它可以像屬性一樣被調(diào)用,這時候我們通常給類的方法添加@property修飾符:
class Circle(object): def __init__(self,radius): self.radius = radius @property def area(self): print("calculate area") return 3.14 * self.radius * 2 circle = Circle(4) print(circle.area) #calculate area #25.12
但是這么做,雖然area可以當(dāng)作一個屬性訪問,但是并不是真正的變成了一個屬性,同時,我們每次調(diào)用circle.area,都會從頭到尾執(zhí)行一遍函數(shù),我們來看下面的例子:
class Circle(object): def __init__(self,radius): self.radius = radius @property def area(self): print("calculate area") return 3.14 * self.radius * 2 c = Circle(4) print(c.__dict__) print(c.area) print(c.area) print(c.__dict__)
輸出為:
{'radius': 4}
calculate area
25.12
calculate area
25.12
{'radius': 4}
可以發(fā)現(xiàn):
- 每次執(zhí)行circle.area,整個函數(shù)流程都會被執(zhí)行一次
- 同時area也沒有真正變成對象的屬性,dict中并沒有area
深入
那么我們有沒有辦法把一個類中的函數(shù)真正變成對象的屬性,同時只有在第一次調(diào)用時進行一次計算,而之后每次調(diào)用不會重復(fù)計算呢?這就是Python中的lazy property。
本文介紹兩種方法。一種是使用python描述符,另一種是使用python修飾符。
1、使用python描述符
class lazy(object): def __init__(self, func): self.func = func def __get__(self, instance, cls): val = self.func(instance) setattr(instance, self.func.__name__, val) return val class Circle(object): def __init__(self, radius): self.radius = radius @lazy def area(self): print("calculate area") return 3.14 * self.radius ** 2 c = Circle(4) print('before calculate area') print(c.__dict__) print(c.area) print(c.area) print('after calculate area') print(c.__dict__) c.radius = 5 print(c.__dict__) print(c.area)
輸出為:
before calculate area
{'radius': 4}
calculate area
50.24
50.24
after calculate area
{'radius': 4, 'area': 50.24}
{'radius': 5, 'area': 50.24}
50.24
{'radius': 5, 'area': 50.24}
可以看到,area只在第一次調(diào)用時計算了一次,同時在調(diào)用以后area變成了對象的一個屬性,同時值并不隨半徑的變化而變化。
在這里,lazy類有__get__
方法,說明是個描述器,第一次執(zhí)行c.area的時候,因為順序問題,先去c.__dict__
中找,沒找到,就去類空間找,在類Circle中,有area()方法,于是就被__get__
攔截。
在__get__
中,調(diào)用實例的area()方法算出結(jié)果,并動態(tài)給實例添加個同名屬性把結(jié)果賦給它,即加到c.__dict__
中去。
再次執(zhí)行c.area的時候,先去c.__dict__
找,因為此時已經(jīng)有了,就不會經(jīng)過area()方法和__get__
了。
2、使用python修飾符
def lazy_property(func): attr_name = "_lazy_" + func.__name__ @property def _lazy_property(instance): if not hasattr(instance, attr_name): setattr(instance, attr_name, func(instance)) return getattr(instance, attr_name) return _lazy_property class Circle(object): def __init__(self, radius): self.radius = radius @lazy_property def area(self): return 3.14 * self.radius ** 2 c = Circle(4) print('before calculate area') print(c.__dict__) print(c.area) print(c.area) print('after calculate area') print(c.__dict__) c.radius = 5 print(c.__dict__) print(c.area)
輸出為:
before calculate area
{'radius': 4}
50.24
50.24
after calculate area
{'radius': 4, '_lazy_area': 50.24}
{'radius': 5, '_lazy_area': 50.24}
50.24
可以看到,area只在第一次調(diào)用時計算了一次,同時在調(diào)用以后area變成了對象的一個屬性,同時值并不隨半徑的變化而變化。
到此這篇關(guān)于Python中l(wèi)azy property的兩種方法小結(jié)的文章就介紹到這了,更多相關(guān)Python lazy property內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python如何寫入Pandas DataFrame到CSV文件
Pandas是一個功能強大的Python數(shù)據(jù)分析庫,常用于處理和分析數(shù)據(jù),CSV文件是一種廣泛使用的數(shù)據(jù)交換格式,Pandas通過to_csv方法支持將DataFrame寫入CSV文件,此方法允許用戶指定分隔符、編碼和選擇性寫入特定列等2024-09-09Python基礎(chǔ)請求庫urllib模塊使用深入探究
在Python中,urllib庫是一個強大的模塊,用于處理URLs,它包含了多個子模塊,其中urllib.request是用于發(fā)出HTTP請求的核心組件,本文將深入探討urllib的基本使用、高級功能以及一些實際場景的示例,方便更全面地了解這個重要的網(wǎng)絡(luò)請求工具2024-01-01