欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python裝飾器中常用的functools.wraps的使用

 更新時(shí)間:2025年08月29日 09:49:01   作者:青衫客36  
functools.wraps是Python裝飾器開(kāi)發(fā)中的關(guān)鍵工具,下面就就來(lái)介紹一下Python裝飾器中常用的functools.wraps的使用,感興趣的可以了解一下

functools.wraps 是 Python 裝飾器開(kāi)發(fā)中非常關(guān)鍵、但常被忽視的工具。它不僅是代碼“優(yōu)雅性”的體現(xiàn),還直接影響調(diào)試、文檔生成、反射等功能的準(zhǔn)確性。

一、什么是functools.wraps?

functools.wraps 是一個(gè)裝飾器,它用于 將被裝飾函數(shù)的元信息(如名稱(chēng)、文檔、注解等)復(fù)制到裝飾器內(nèi)部的包裝函數(shù)上。

為什么需要它?

來(lái)看一個(gè)沒(méi)有使用 wraps 的裝飾器:

def logger(func):
    def wrapper(*args, **kwargs):
        print("調(diào)用函數(shù)")
        return func(*args, **kwargs)
    return wrapper

@logger
def add(a, b):
    """計(jì)算兩個(gè)數(shù)的和"""
    return a + b

此時(shí):

print(add.__name__)     # ? wrapper
print(add.__doc__)      # ? None

我們調(diào)用的是 add(),但其實(shí) add 是 wrapper,元信息丟失了。

二、解決方案:使用functools.wraps

from functools import wraps

def logger(func):
    @wraps(func)  # ?? 關(guān)鍵:復(fù)制原函數(shù)的元信息
    def wrapper(*args, **kwargs):
        print("調(diào)用函數(shù)")
        return func(*args, **kwargs)
    return wrapper

@logger
def add(a, b):
    """計(jì)算兩個(gè)數(shù)的和"""
    return a + b

現(xiàn)在輸出:

print(add.__name__)  # ? add
print(add.__doc__)   # ? 計(jì)算兩個(gè)數(shù)的和

三、底層原理分析:@wraps做了什么?

functools.wrapsfunctools.update_wrapper 的語(yǔ)法糖。

等價(jià)于:

@wraps(func)
def wrapper(): ...

# 等價(jià)于
def wrapper(): ...
wrapper = functools.update_wrapper(wrapper, func)

update_wrapper(wrapper, func)會(huì)做這些事:

屬性被復(fù)制
__module__模塊名
__name__函數(shù)名
__qualname__完整限定名(含類(lèi)名)
__annotations__參數(shù)類(lèi)型注解
__doc__文檔字符串
__dict__自定義屬性字典(保持裝飾器后可追加屬性)

四、源碼分析:wraps的定義

來(lái)自 Python 標(biāo)準(zhǔn)庫(kù) functools.py

def wraps(wrapped,
          assigned=WRAPPER_ASSIGNMENTS,     # 默認(rèn):__module__, __name__, __qualname__, __annotations__, __doc__
          updated=WRAPPER_UPDATES):         # 默認(rèn):__dict__
    def decorator(wrapper):
        return update_wrapper(wrapper, wrapped, assigned, updated)
    return decorator

所以 @wraps(func) 是返回了一個(gè)“裝飾器”,給你的 wrapper() 做屬性復(fù)制。

五、實(shí)用場(chǎng)景總結(jié)

場(chǎng)景說(shuō)明
? 調(diào)試保留原函數(shù)名,調(diào)試信息更準(zhǔn)確
? 文檔生成help(func)、Sphinx 等能讀取 docstring
? 反射與 introspectioninspect.getfullargspec(func) 能得到正確參數(shù)信息
? functools.cache / lru_cache依賴(lài)函數(shù)的 __name__ 和 __hash__,否則緩存可能出錯(cuò)
? unittest mock.patchpatch 也需要定位原函數(shù),名字不能丟
? IDE提示 / 自動(dòng)補(bǔ)全wrapper.__annotations__ 有利于類(lèi)型推斷和補(bǔ)全支持

六、完整示例對(duì)比

1. 單層嵌套裝飾器

? 不使用wraps

def log(func):
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

@log
def hello(name: str):
    """打招呼"""
    return f"Hi, {name}"

print(hello.__name__)        # wrapper
print(hello.__doc__)         # None
print(hello.__annotations__) # {}

? 使用wraps

from functools import wraps

def log(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

輸出:

hello.__name__         # hello
hello.__doc__          # 打招呼
hello.__annotations__  # {'name': <class 'str'>}

2. 多層嵌套裝飾器(以2層嵌套為例)

? 不使用wraps

def decorator1(func):
    def wrapper(*args, **kwargs):
        """wrapper doc 1"""
        return func(*args, **kwargs)

    return wrapper


def decorator2(func):
    def wrapper(*args, **kwargs):
        """wrapper doc 2"""
        return func(*args, **kwargs)

    return wrapper


@decorator1
@decorator2
def my_function():
    """This is the original function"""
    print("Hello")


print(my_function.__name__)  # wrapper
print(my_function.__doc__)  # wrapper doc 1

多個(gè)裝飾器會(huì)逐層覆蓋原函數(shù)的元信息(metadata),比如 __name__、__doc__。在上述程序中,decorator2 返回一個(gè)新的函數(shù) wrapper,decorator1 再包裝這個(gè)新的函數(shù),得到另一個(gè)新的 wrapper,每一層 wrapper 都是新的函數(shù)對(duì)象,并沒(méi)有自動(dòng)保留原函數(shù)的 __name__、__doc__、__annotations__ 等屬性。

? 使用wraps

from functools import wraps


def decorator1(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """wrapper doc 1"""
        return func(*args, **kwargs)

    return wrapper


def decorator2(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """wrapper doc 2"""
        return func(*args, **kwargs)

    return wrapper


@decorator1
@decorator2
def my_function():
    """This is the original function"""
    print("Hello")


print(my_function.__name__)  # my_function
print(my_function.__doc__)  # This is the original function

對(duì)于多層裝飾器的情況,建議每一層裝飾器都應(yīng)該加 @wraps(func),否則元信息只保留最外層那一層的,并且在多層裝飾器鏈中,調(diào)試會(huì)非?;靵y

?? 七、常見(jiàn)誤區(qū)

錯(cuò)誤原因
忘記加 @wraps實(shí)際上丟掉了原函數(shù)元信息
wraps() 用錯(cuò)了對(duì)象必須傳的是“要包裝的原函數(shù)”
把 wraps 當(dāng)成執(zhí)行函數(shù)它本身是個(gè)“返回裝飾器的函數(shù)”
多層嵌套裝飾器未層層使用 wraps每一層都需要加 @wraps(func)

?? 八、總結(jié)

  • ? 凡是寫(xiě)裝飾器 ? wrapper 外面加 @wraps(func)
  • ? 目的是:保留函數(shù)元信息,防止“身份丟失”
  • ? 等價(jià)于:update_wrapper(wrapper, func)
  • ? 一般配合 functools 系列使用,如:@lru_cache、@cache_property

?? 最佳實(shí)踐模板

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        # 執(zhí)行前邏輯
        result = func(*args, **kwargs)
        # 執(zhí)行后邏輯
        return result
    return wrapper

到此這篇關(guān)于Python裝飾器中常用的functools.wraps的使用的文章就介紹到這了,更多相關(guān)Python functools.wraps內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python?lazypredict構(gòu)建大量基本模型簡(jiǎn)化機(jī)器學(xué)習(xí)

    python?lazypredict構(gòu)建大量基本模型簡(jiǎn)化機(jī)器學(xué)習(xí)

    這篇文章主要介紹了python?lazypredict構(gòu)建大量基本模型簡(jiǎn)化機(jī)器學(xué)習(xí),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • python 將html轉(zhuǎn)換為pdf的幾種方法

    python 將html轉(zhuǎn)換為pdf的幾種方法

    這篇文章主要介紹了python 將html轉(zhuǎn)換為pdf的幾種方法,幫助大家更好的理解和使用python,感興趣的朋友可以了解下
    2020-12-12
  • 使用Python實(shí)現(xiàn)音頻降噪功能

    使用Python實(shí)現(xiàn)音頻降噪功能

    在音頻處理領(lǐng)域,背景噪聲是一個(gè)常見(jiàn)的問(wèn)題,為了提高音頻的質(zhì)量,我們需要對(duì)音頻進(jìn)行降噪處理,本文將介紹如何使用 Python 實(shí)現(xiàn)音頻降噪,文中通過(guò)代碼示例講解的非常詳細(xì),需要的朋友可以參考下
    2024-11-11
  • Python安裝Bs4的多種方法

    Python安裝Bs4的多種方法

    這篇文章主要介紹了Python安裝Bs4幾種方法,本文通過(guò)多種方法給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Python實(shí)現(xiàn)快速替換Word文檔中的關(guān)鍵字

    Python實(shí)現(xiàn)快速替換Word文檔中的關(guān)鍵字

    使用Python自動(dòng)化處理Word文檔可以幫助您提高效率,并減少手動(dòng)處理文檔所需的時(shí)間和精力,所以本文為大家準(zhǔn)備了Python快速替換Word文檔中的關(guān)鍵字的方法,希望對(duì)大家有所幫助
    2023-06-06
  • python和anaconda區(qū)別以及先后安裝的問(wèn)題詳解

    python和anaconda區(qū)別以及先后安裝的問(wèn)題詳解

    Anaconda(開(kāi)源的Python包管理器)是一個(gè)python發(fā)行版,包含了conda、Python等180多個(gè)科學(xué)包及其依賴(lài)項(xiàng),下面這篇文章主要給大家介紹了關(guān)于python和anaconda區(qū)別以及先后安裝問(wèn)題的相關(guān)資料,需要的朋友可以參考下
    2022-05-05
  • 使用OpenCV為圖像加水印的教程

    使用OpenCV為圖像加水印的教程

    通過(guò)本文學(xué)習(xí)將學(xué)會(huì)如何使用 OpenCV 為多個(gè)圖像添加水印,在 OpenCV 中調(diào)整圖像大小也很方便,對(duì)OpenCV圖像加水印相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-09-09
  • Python NumPy實(shí)現(xiàn)數(shù)組排序與過(guò)濾示例分析講解

    Python NumPy實(shí)現(xiàn)數(shù)組排序與過(guò)濾示例分析講解

    NumPy是Python的一種開(kāi)源的數(shù)值計(jì)算擴(kuò)展,它支持大量的維度數(shù)組與矩陣運(yùn)算,這篇文章主要介紹了使用NumPy實(shí)現(xiàn)數(shù)組排序與過(guò)濾的方法,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-05-05
  • python網(wǎng)絡(luò)編程之TCP通信實(shí)例和socketserver框架使用例子

    python網(wǎng)絡(luò)編程之TCP通信實(shí)例和socketserver框架使用例子

    這篇文章主要介紹了python網(wǎng)絡(luò)編程之TCP通信實(shí)例和socketserver框架使用例子,需要的朋友可以參考下
    2014-04-04
  • Python分支語(yǔ)句常見(jiàn)的使用方法

    Python分支語(yǔ)句常見(jiàn)的使用方法

    這篇文章主要介紹了Python分支語(yǔ)句常見(jiàn)的使用方法,Python分支語(yǔ)句,也稱(chēng)為選擇語(yǔ)句,體現(xiàn)了程序的選擇結(jié)構(gòu),即對(duì)應(yīng)不同的場(chǎng)景,選擇不同的處理方式,具體常見(jiàn)的用法需要的朋友可參考下面文章內(nèi)容
    2022-06-06

最新評(píng)論