七個常用<python裝飾器>---足夠改進代碼質量 (保姆詳解)

前言:

寫代碼嘛,關鍵是得讓它既好用又好看,這不,Python裝飾器就擺在那兒。咱們程序員有時也得有那么點藝術家的腔調:講求效率,追求代碼的簡潔優雅,偶爾還得裝裝X,不是嗎?
翻開人家的工程代碼,哎呦,有時候我都忍不住想吐槽,怎么就這么啰嗦?這不,咱就得拿出刀子,削削刻刻,把裝飾器這玩意兒的妙用給咱整明白了。得讓代碼那叫一個流暢,看著清清楚楚,懂得一看就會,會了還想看。

正文:

1.?@staticmethod

作用

@staticmethod 裝飾器允許我們定義一個方法,使其不依賴于對象的狀態(即不與特定的實例self綁定,也不與類cls綁定)。這主要用在你想將某個功能置于類的命名空間(namespace)下,以表明它邏輯上屬于類,但實際上又獨立于類的任何特定實例。


用法

當你需要直接通過類調用方法而不需要實例時,將該方法定義為靜態方法是非常合適的。
class MathOperations:@staticmethoddef add(x, y):"""返回兩個參數的和。"""return x + y# 調用靜態方法,注意如何使用類名直接調用靜態方法,而不是類的實例
result = MathOperations.add(5, 10)
print(result)  # 輸出: 15

代碼講解

在上述代碼中,add 方法被 @staticmethod 裝飾,意味著它不接受常規方法第一個參數(self)。這使得它可以像普通函數一樣通過類名直接調用,而不需要創建類的實例。


對比

不使用 @staticmethod 的普通方法會要求傳遞一個實例作為第一個參數。下面是未使用 @staticmethod 的對比:
class MathOperations:def add(self, x, y):"""返回兩個參數的和。需要通過實例調用。"""return x + y# 創建類的實例
math_ops = MathOperations()
result = math_ops.add(5, 10)
print(result)  # 輸出: 15

在這個例子中,我們必須先創建一個 MathOperations 類的實例,并通過這個實例調用 add 方法。


2.@classmethod

作用

@classmethod 裝飾器使方法變成類方法,它接收類本身作為第一個參數,通常命名為 cls。這使得這個方法可以訪問類屬性或調用其他類方法,而不依賴于具體的實例。


用法

類方法通常用作替代構造函數。
class MyClass:_my_list = []@classmethoddef add_to_list(cls, item):"""將項目添加到類屬性列表中。"""cls._my_list.append(item)MyClass.add_to_list('item 1')
print(MyClass._my_list)  # 輸出: ['item 1']

代碼講解

在上述代碼中,add_to_list 方法是一個類方法,可以直接通過類來調用,并且它修改了類屬性 _my_list。


對比

常規的實例方法需要創建實例才能調用,并且只能訪問實例屬性:
class MyClass:def __init__(self):self._my_list = []def add_to_list(self, item):"""將項目添加到實例屬性列表中。"""self._my_list.append(item)# 創建類的實例
my_instance = MyClass()
my_instance.add_to_list('item 1')
print(my_instance._my_list)  # 輸出: ['item 1']# 嘗試使用類名直接調用將會失敗
# MyClass.add_to_list('item 1')  # 這將拋出 TypeError

3.?@property

作用

@property 裝飾器用于將類中的方法當作一個屬性來訪問,通常用于計算或返回內部狀態的值,同時不讓調用者直接訪問內部狀態。


用法

它經常被用于創建只讀屬性。
class MyClass:def __init__(self, value):self._internal_state = value@propertydef internal_state(self):"""訪問內部狀態的一個只讀屬性"""return self._internal_state# 創建類實例
instance = MyClass(5)
print(instance.internal_state)  # 輸出: 5

代碼講解

在上面的代碼中,internal_state 成為一個只讀屬性,我們不能直接對它賦值(除非也定義了 setter)。


對比

沒有 @property 裝飾器,我們通常會直接公開屬性或通過一個明確的 getter 方法來訪問:
class MyClass:def __init__(self, value):self.internal_state = value# 創建類實例
instance = MyClass(5)
print(instance.internal_state)  # 輸出: 5

在這個例子中,internal_state 可以被外部直接訪問和修改,沒有了 @property 提供的保護層。

4.?@property.setter

作用

@property.setter 裝飾器是與之前的 @property 配套使用的,它允許我們定義一個賦值方法,可以通過這個屬性對相關數據進行設置。


用法

我們可以用它來定義一個屬性的設置邏輯,例如實施類型檢查或值驗證。
class MyClass:def __init__(self, value):self._internal_state = value@propertydef internal_state(self):return self._internal_state@internal_state.setterdef internal_state(self, value):if not isinstance(value, int):raise ValueError("internal_state must be an integer")self._internal_state = value# 創建類實例
instance = MyClass(5)
instance.internal_state = 10  # 有效
print(instance.internal_state)  # 輸出: 10

代碼講解

在這個例子中,嘗試為 internal_state 賦非整數值會引發 ValueError,因為我們的 setter 方法中添加了類型檢查。


對比

如果沒有 @property.setter,我們不能定義一個屬性的賦值行為,屬性將是完全公開的:
class MyClass:def __init__(self, value):self.internal_state = value# 創建類實例
instance = MyClass(5)
instance.internal_state = 'a string'  # 沒有問題,但可能不是我們想要的行為

在沒有 setter 裝飾器的情況下,internal_state 屬性可以接受任何類型的賦值,沒有額外的驗證邏輯來保護類的內部表示。

5.?@functools.wraps

作用

裝飾器在Python中用于增加函數額外的功能,但裝飾器會改變函數的__name__和__doc__屬性。@functools.wraps是一個特殊的裝飾器,用于在定義裝飾器時保持原函數的元數據不變。


用法

這通常用于自定義裝飾器的編寫中,以確保被裝飾函數的元數據不會丟失。
import functoolsdef my_decorator(func):@functools.wraps(func)def wrapper(*args, **kwargs):print("函數發生前...")result = func(*args, **kwargs)print("函數發生后")return resultreturn wrapper@my_decorator
def say_hello():"""Greet the user."""print("Hello!")# 由于使用了 functools.wraps,say_hello 保留了其原始的元數據
print(say_hello.__name__)  
print(say_hello.__doc__)   

代碼講解

在這個例子中,functools.wraps用在內部函數wrapper上,保護了原始函數say_hello的__name__和__doc__屬性。如果不使用functools.wraps,say_hello.__name__將會返回'wrapper'。


對比

沒有@functools.wraps,函數say_hello的屬性會被丟失:
def my_decorator(func):def wrapper(*args, **kwargs):"""Wrapper function for func."""print("函數get前發生的...")result = func(*args, **kwargs)print("函數get后發生的...")return resultreturn wrapper@my_decorator
def say_hello():print("Hello!")# 沒有使用 functools.wraps,元數據被覆蓋了
print(say_hello.__name__) 
print(say_hello.__doc__)   

在沒有使用functools.wraps的這個版本中,裝飾函數wrapper的__name__和__doc__覆蓋了say_hello的元數據,這會在某些情況下導致混淆,特別是在需要函數簽名保持原樣時。

6.?@functools.lru_cache

作用

@functools.lru_cache 提供了一個簡單的緩存機制,讓函數能緩存最近使用過的輸入及其結果。如果一個函數被頻繁調用,并且伴隨相同的參數,LRU(Least Recently Used)緩存可以提升性能。


用法

它特別用于那些計算開銷大但又有高重復調用概率的函數。
import functools@functools.lru_cache(maxsize=32)
def fibonacci(num):"""返回斐波那契數列的第 num 個數"""if num < 2:return numreturn fibonacci(num - 1) + fibonacci(num - 2)# 第一次調用將會緩存結果
print(fibonacci(10))  # 輸出: 55
# 后續調用將會使用緩存
print(fibonacci(10))  # 輸出: 55

代碼講解

在這個例子中,fibonacci 函數的每個結果會在首次計算后緩存起來。當你再次用同樣的參數調用該函數時,它會返回緩存的結果而不是重新計算。


對比

不使用 @functools.lru_cache 運行上面的 fibonacci 函數會導致很多重復的計算,特別是參數較大時會非常耗時。

7.?@functools.singledispatch

作用

@functools.singledispatch 裝飾器可以將普通函數轉化為單分派泛函數。這表示函數將會根據第一個參數的類型,調用另外專門定義的函數,實現類似于其他語言中的函數重載。


用法

它特別適用于需要根據不同類型執行不同操作的場景。
import functools@functools.singledispatch
def format_data(arg):"""默認的實現,被調用時參數類型沒有匹配的特定注冊函數"""return str(arg)@format_data.register
def _(arg: int):"""專門用于處理整數的實現"""return f"{arg} is an integer"@format_data.register
def _(arg: list):"""專門用于處理列表的實現"""return f"List length is {len(arg)} and items are {', '.join(map(str, arg))}"# 根據參數類型調用不同的實現
print(format_data("Hello!")) 
print(format_data(42))       
print(format_data([1, 2, 3])) 

代碼講解

在這個例子中,對于任意未注冊類型,format_data 將使用默認實現,即直接轉換為字符串。對于被注冊類型,例如 int 和 list,將調用專為它們定義的函數。


對比

若沒有 @functools.singledispatch,你通常需要編寫顯式的類型檢查語句(如使用 if-elif-else 結構),這樣的代碼通常會更加冗長和不易維護。

總結:

好了,我的粉兒們,咱們今天的`裝飾器課`就上到這兒。

記住,裝飾器不光讓你的代碼行數變短,顏值變高,更重要的是,它能讓你的工作流、邏輯變得更清晰

  1. @staticmethod@classmethod能幫你搞定靜態和類相關的調用;
  2. @property 讓訪問方法像是讀取屬性一樣優雅;
  3. @functools.wraps,讓你自定義裝飾器的時候還能保持原函數的尊嚴和名聲。
  4. 然后是咱們的性能加速器@functools.lru_cache,讓你對那些費勁兒的計算結果記個小本本,下次用的時候直接從記憶里找,不再重新煮沸冷飯,節約不少腦力。
  5. 至于@functools.singledispatch,簡直就是動態語言Python的類型掛鉤利器,讓同一個名字的函數根據傳參的不同表演不同的戲法。


啰嗦了這么多,希望你們明白:代碼寫得好不好,跟會不會用裝飾器,那可是直接掛鉤的。用好了,你的代碼就像是精品咖啡,不用或者用糟了,那就是旅館速溶。行了,回家練去吧。

保持好奇,保持饑渴,這樣才能寫出更香的代碼。加油!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/210340.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/210340.shtml
英文地址,請注明出處:http://en.pswp.cn/news/210340.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SpringSecurity6 | 自定義認證規則

?作者簡介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;熱愛Java后端開發者&#xff0c;一個想要與大家共同進步的男人&#x1f609;&#x1f609; &#x1f34e;個人主頁&#xff1a;Leo的博客 &#x1f49e;當前專欄&#xff1a; Java從入門到精通 ?特色專欄&#xf…

移相干涉技術1-多種干涉條紋仿真模擬生成(原理轉載+代碼實現 包括模擬生成干涉條紋圖)

過去的干涉測量技術是通過人的肉眼或者相機拍攝&#xff0c;來直觀判斷干涉圖中條紋特征進而完成測量&#xff0c;該方法的不穩定因素&#xff08;比如人的主觀意志&#xff09;很多&#xff0c;其精度誤差在/10左右38]&#xff1b;現代干涉測量技術通過將電子技術、計算機技術…

智能優化算法應用:基于廚師算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼

智能優化算法應用&#xff1a;基于廚師算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼 文章目錄 智能優化算法應用&#xff1a;基于廚師算法無線傳感器網絡(WSN)覆蓋優化 - 附代碼1.無線傳感網絡節點模型2.覆蓋數學模型及分析3.廚師算法4.實驗參數設定5.算法結果6.參考文獻7.MATLAB…

代碼隨想錄-刷題第二十一天

530.二叉搜索樹的最小絕對差 題目鏈接&#xff1a;530. 二叉搜索樹的最小絕對差 思路&#xff1a;二叉搜索樹的中序遍歷是有序的。根據二叉搜索樹的這個特性來解題。 class Solution {// 同樣利用二叉樹中序遍歷是一個有序數組。private List<Integer> list new Arra…

一加 12 Pop-up快閃活動來襲,十城聯動火爆開啟

12 月 9 日&#xff0c;一加 12 Pop-up 快閃活動在北京、深圳、上海、廣州等十城聯動開啟&#xff0c;各地加油歡聚快閃現場&#xff0c;搶先體驗與購買一加 12。作為一加十年超越之作&#xff0c;一加 12 全球首發擁有醫療級護眼方案和行業第一 4500nit 峰值亮度的 2K 東方屏、…

C++新經典模板與泛型編程:策略類模板

策略類模板 在前面的博文中&#xff0c;策略類SumPolicy和MinPolicy都是普通的類&#xff0c;其中包含的是一個靜態成員函數模板algorithm()&#xff0c;該函數模板包含兩個類型模板參數。其實&#xff0c;也可以把SumPolicy和MinPolicy類寫成類模板—直接把algorithm()中的兩…

【Linux】無法使用 ifconfig 查看系統網絡接口信息,報錯 command not found: ifconfig

問題描述 ifconfig是一個用于配置和顯示系統網絡接口信息的命令行工具。它通常用于Unix、Linux和其他類Unix系統中。 通過ifconfig命令&#xff0c;你可以查看和修改系統中網絡接口的配置信息&#xff0c;包括IP地址、子網掩碼、MAC地址、MTU&#xff08;最大傳輸單元&#x…

javacv踩坑記錄

前一陣學習opencv&#xff0c;發現在做人臉識別的時候遇到一些類庫不存在的情況&#xff0c;查找后發現是由于拓展包沒有安裝完全&#xff08;僅安裝了基礎版&#xff09;。由于網絡的問題&#xff08;初步猜測&#xff09;&#xff0c;始終無法安裝好拓展包。 于是另辟蹊徑&am…

MongoDb數據庫

一、命令交互 1.1 數據庫命令 1.顯示所有數據庫&#xff1a; show dbs 2.切換到指定數據庫&#xff0c;如果沒有則自動創建數據庫 use databaseName 3.顯示當前所在數據庫 db 4.刪除當前數據庫 use 庫名 db.dropDatabase() 1.2 集合命令 1.創建集合 db.createColl…

[文檔級關系抽取|ACL論文]文檔級關系抽取中語言理解的基礎模型

Did the Models Understand Documents? Benchmarking Models for Language Understanding in Document-Level Relation Extraction School of Computer Science, Fudan University | ACL 2023.06 | 原文鏈接 Background 過去的工作大多數都是從單個句子中收獲更多的關系&am…

MongoDB中的$type操作符和limit與skip方法

本文主要介紹MongoDB中的$type操作符和limit與skip方法。 目錄 MongoDB的$type操作符MongoDB的limit方法MongoDB的skip方法 MongoDB的$type操作符 MongoDB中的$type操作符用于檢查一個字段的類型是否與指定的類型相匹配。它可以用于查詢和投影操作。 $type操作符可以與以下數…

php,redis實現一個電影熱度排行榜

要實現電影熱度排行榜&#xff0c;需要記錄每個電影的熱度值&#xff0c;熱度值可以根據不同的算法計算&#xff0c;例如&#xff1a;觀看次數、評分數、評論數等。這里我們以觀看次數為例。 首先&#xff0c;需要使用 Redis 的 Sorted Set 數據結構來存儲電影的熱度值和電影 …

JVS低代碼表單引擎:數據校驗與處理的先鋒

隨著信息技術的迅速發展&#xff0c;數據校驗與處理已經成為了各類應用中不可或缺的一環。尤其是在涉及敏感信息&#xff0c;如密碼處理時&#xff0c;其安全性和準確性顯得尤為重要。JVS低代碼表單引擎提供了強大的文本組件觸發邏輯校驗功能&#xff0c;它能夠在用戶填寫數據的…

截取字符串

輸入一個字符串和一個整數 k &#xff0c;截取字符串的前k個字符并輸出。 數據范圍&#xff1a;字符串長度滿足 1≤n≤1000&#xff0c; 1≤k≤n 輸入描述&#xff1a; 1.輸入待截取的字符串 2.輸入一個正整數k&#xff0c;代表截取的長度 輸出描述&#xff1a;截取后的字符串…

模電·放大電路的分析方法——等效電路法

放大電路的分析方法——等效電路法 晶體管的直流模型及靜態工作點的估算法晶體管共射h參數等效模型 h h h參數等效模型的由來參數的物理意義簡化的h參數等效模型 r b e {r\tiny be} rbe的近似表達式 共射放大電路動態參數的分析電壓放大倍數 A ˙ u \.{A}\tiny u A˙u輸入電阻 …

三種配置Spring程序的方法

1 使用XML文件配置Spring程序 在XML文件中使用bean標簽&#xff0c;將其交給容器管理 class: 指定bean對應的類型的全限定名稱id: 用于指定一個名稱&#xff0c;作為該bean的唯一標識符&#xff0c;如果不需要id&#xff0c;也可不指定該屬性name: 用于指定bean的別名&#x…

【小米電腦管家】安裝使用教程--非小米電腦

安裝說明功能體驗下載資源 Xiaomi HyperOS發布后&#xff0c;小米妙享電腦端獨立版本也走向終點&#xff0c;最新的【小米電腦管家】將會內置妙享實現萬物互聯。那么本篇文章將分享非小米電腦用戶如何繞過設備識別驗證安裝使用【小米電腦管家】實現萬物互聯 安裝說明 1.解壓文…

如何用Python編寫俄羅斯方塊Tetris游戲?

在本文中&#xff0c;我們將用Python代碼構建一個令人驚嘆的項目&#xff1a;俄羅斯方塊游戲。在這個項目中&#xff0c;我們將使用pygame庫來構建游戲。要創建此項目&#xff0c;請確保您的系統中安裝了最新版本的Python。讓我們開始吧&#xff01; Pygame是一組跨平臺的Pyth…

wireshark過濾包小技巧

1、過濾包含某個字符串的數據包&#xff1a; 或者&#xff1a; 2、過濾包含某一連續十六進制的數據包&#xff1a; 或者&#xff1a; 3、過濾精確到位數位置 或者&#xff1a;

關于使用EB tresos出現無法激活的情況解決

EB安裝完成時需要激活才能使用的&#xff0c;不然都無法建立工程。 我在安裝eb studio時就是在激活方面有問題導致無法使用&#xff0c;下面講解出現了什么問題以及我如何去解除的。 1.出現的錯誤提示&#xff1f; ERROR&#xff1a;flexActAPPActivationSend按照在官網中&…