Python編程通過懶屬性提升性能
懶加載是一種編程范式,它推遲加載操作,直到不得不這樣做。通常,當操作開銷很大,需要耗費大量時間或空間時,惰性求值是首選實現(xiàn)。例如,在 Python 中,涉及惰性求值的最著名技術(shù)之一是生成器。生成器不是為迭代創(chuàng)建整個序列,而是懶惰地一次生成一個元素。
在 Python 世界之外,許多其他面向?qū)ο蟮木幊陶Z言,例如 Swift 和 Kotlin,都具有與對象相關(guān)的惰性求值。具體來說,你可以指定自定義實例對象的特定屬性是惰性的,這意味著在顯式訪問這些屬性之前不會創(chuàng)建這些屬性。
為什么需要懶加載
在我們開始討論懶屬性之前,有些人可能想知道為什么它很重要,或者我們?yōu)槭裁匆褂脩袑傩浴?/p>
比如在社交網(wǎng)站中,一個功能是查看一個人的關(guān)注者,以列表的形式呈現(xiàn)。當我們點擊一個用戶時,我們可以在彈出窗口中查看該用戶的個人資料。獲取用戶個人資料數(shù)據(jù)的操作可能很昂貴,不僅需要訪問遠程服務(wù)器,還需要將數(shù)據(jù)存儲在內(nèi)存中。
那么在編程實現(xiàn)時可以把關(guān)注者的個人資料作為懶屬性,僅在點擊特定用戶名時才獲取該屬性。
這就是為什么我們需要懶屬性。
如何使用懶加載
方法 1:
使用 @property
@property 是一個裝飾器,可以將常規(guī)函數(shù)轉(zhuǎn)化為屬性,比如支持點符號訪問。因此,嚴格來說,創(chuàng)建屬性并不是真正創(chuàng)建懶屬性本身。相反,它只是提供一個接口來簡化數(shù)據(jù)處理的問題。讓我們先看看下面的代碼。
class User: def __init__(self): self._profile_data = None @property def profile_data(self): if self._profile_data is None: print("執(zhí)行耗時操作...") self._profile_data = 'profile data' return self._profile_data demo = User() print("init done") print(demo.profile_data) #init done #執(zhí)行耗時操作... #profile data
初始化完成后并不會執(zhí)行耗時操作,對應(yīng)的加載用戶列表就不會覺得卡。只有在獲取用戶資料(點擊操作)時,程序會先判斷是否已經(jīng)存在 _profile_data,沒有才會執(zhí)行耗時操作,如果有直接返回,大大提升了效率。
方法 2:
使用 __getattr__
特殊方法
在 Python 中,名稱前后有雙下劃線的函數(shù)稱為魔術(shù)方法。__getattr__
可以幫助我們實現(xiàn)懶屬性。
對于自定義類,實例對象的屬性保存在字典中,可以訪問實例對象的 __dict__
屬性獲取。值得注意的是,如果__dict__
不包含指定的屬性,Python 將會調(diào)用魔術(shù)方法 __getattr__
,寫個代碼你就明白了:
class User: def __init__(self): self._profile_data = None self.name = 'None' def __getattr__(self, item): print("called __getattr__") if item == 'profile_data': if self._profile_data is None: print("執(zhí)行耗時操作...") self._profile_data = 'profile data' return self._profile_data user = User() print("init done") print(user.__dict__) print(user.profile_data) print(user.__dict__) print(user.name)
輸出結(jié)果如下:
init done {'_profile_data': None, 'name': 'None'} called __getattr__ 執(zhí)行耗時操作... profile data {'_profile_data': 'profile data', 'name': 'None'} None
和方法 1 一樣,初始化完成后并不會執(zhí)行耗時操作,我們在獲取 profile_data 屬性時,由于 profile_data 不在 __dict__
中,因此會執(zhí)行 __getattr__
方法獲取,而 name 在 __dict__
獲取 name 屬性時根本就不會執(zhí)行 __getattr__
方法。
怎么判斷一個屬性是不是在 __dict__
中呢,只要沒有顯式的定義該屬性,或者使用 setattr 來設(shè)置屬性,它就不會在 __dict__
中。
因此可以借助魔術(shù)方法 __getattr__
來創(chuàng)建懶屬性 profile_data。
需要注意,Python 還有一個類似的魔術(shù)方法 __getattribute__
,與 __getattr__
方法不同的是, 每次獲取屬性時都會調(diào)用 __getattribute__
方法。
class User: def __init__(self): self._profile_data = None self.name = 'None' def __getattribute__(self, item): print("called __getattr__") user = User() print("init done") print(user.profile_data) print(user.name)
程序輸出如下:
init done
called __getattr__
None
called __getattr__
None
此功能僅在你期望屬性非常頻繁地更改并且只有最新數(shù)據(jù)相關(guān)時才有用。在這些情況下,我們可以通過定義相關(guān)函數(shù)來實現(xiàn)效果。換句話說,我不建議你嘗試使用它,因為很容易陷入無限遞歸循環(huán)。
最后的話
在本文中,我們重點討論了在 Python 中實現(xiàn)懶屬性的兩種實用方法:一種使用 @property
裝飾器,另一種使用 __getattr__
特殊方法。
就我個人而言,我更喜歡使用屬性裝飾器,它更直接、更容易理解。但是,當你需要定義多個懶屬性時,該 getattr 方法更好,因為它提供了一個集中的地方來管理這些懶屬性。
以上就是Python編程通過懶屬性提升性能的詳細內(nèi)容,更多關(guān)于Python懶屬性提升性能的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python對站點數(shù)據(jù)做EOF且做插值繪制填色圖
這篇文章主要介紹了python對站點數(shù)據(jù)做EOF且做插值繪制填色圖,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,,需要的小伙伴可以參考一下2022-09-09Python Web框架Flask中使用百度云存儲BCS實例
這篇文章主要介紹了Python Web框架Flask中使用百度云存儲BCS實例,本文調(diào)用了百度云存儲Python SDK中的相關(guān)類,需要的朋友可以參考下2015-02-02python尋找list中最大值、最小值并返回其所在位置的方法
今天小編就為大家分享一篇python尋找list中最大值、最小值并返回其所在位置的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-06-06Python 爬蟲實現(xiàn)增加播客訪問量的方法實現(xiàn)
這篇文章主要介紹了Python 爬蟲實現(xiàn)增加播客訪問量的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-10-10Python3 利用face_recognition實現(xiàn)人臉識別的方法
這篇文章主要介紹了Python3 利用face_recognition實現(xiàn)人臉識別的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-03-03