最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

一、什么是functools.wraps?

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

為什么需要它?

來看一個(gè)沒有使用 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 的語法糖。

等價(jià)于:

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

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

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

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

四、源碼分析:wraps的定義

來自 Python 標(biāo)準(zhǔn)庫 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)景說明
? 調(diào)試保留原函數(shù)名,調(diào)試信息更準(zhǔn)確
? 文檔生成help(func)、Sphinx 等能讀取 docstring
? 反射與 introspectioninspect.getfullargspec(func) 能得到正確參數(shù)信息
? functools.cache / lru_cache依賴函數(shù)的 __name__ 和 __hash__,否則緩存可能出錯(cuò)
? unittest mock.patchpatch 也需要定位原函數(shù),名字不能丟
? IDE提示 / 自動(dòng)補(bǔ)全wrapper.__annotations__ 有利于類型推斷和補(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ì)象,并沒有自動(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

?? 七、常見誤區(qū)

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

?? 八、總結(jié)

  • ? 凡是寫裝飾器 ? 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)文章

  • Django中如何使用sass的方法步驟

    Django中如何使用sass的方法步驟

    這篇文章主要介紹了Django中如何使用sass的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • python自定義函數(shù)中的return和print使用及說明

    python自定義函數(shù)中的return和print使用及說明

    這篇文章主要介紹了python自定義函數(shù)中的return和print使用及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • python顏色隨機(jī)生成器的實(shí)例代碼

    python顏色隨機(jī)生成器的實(shí)例代碼

    這篇文章主要介紹了python顏色隨機(jī)生成器的實(shí)例代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-01-01
  • 詳解利用Python制作中文漢字雨效果

    詳解利用Python制作中文漢字雨效果

    這篇文章主要介紹了如何利用Python中的Pygame模塊實(shí)現(xiàn)中文漢字雨效果,文中通過示例代碼介紹的非常詳細(xì),感興趣的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-03-03
  • Python pyecharts繪制柱狀圖

    Python pyecharts繪制柱狀圖

    這篇文章主要介紹了Python pyecharts繪制柱狀圖,文章介紹的柱狀/條形圖,通過柱形的高度/條形的寬度來表現(xiàn)數(shù)據(jù)的大小,感興趣的小伙伴一起進(jìn)入文章學(xué)習(xí)更詳細(xì)內(nèi)容吧
    2021-12-12
  • 利用python循環(huán)創(chuàng)建多個(gè)文件的方法

    利用python循環(huán)創(chuàng)建多個(gè)文件的方法

    今天小編就為大家分享一篇利用python循環(huán)創(chuàng)建多個(gè)文件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-10-10
  • 對(duì)Python中創(chuàng)建進(jìn)程的兩種方式以及進(jìn)程池詳解

    對(duì)Python中創(chuàng)建進(jìn)程的兩種方式以及進(jìn)程池詳解

    今天小編就為大家分享一篇對(duì)Python中創(chuàng)建進(jìn)程的兩種方式以及進(jìn)程池詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-01-01
  • 巧妙使用python?opencv庫玩轉(zhuǎn)視頻幀率

    巧妙使用python?opencv庫玩轉(zhuǎn)視頻幀率

    這篇文章主要介紹了巧妙使用python?opencv庫玩轉(zhuǎn)視頻幀率的教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • python redis連接 有序集合去重的代碼

    python redis連接 有序集合去重的代碼

    這篇文章主要介紹了python redis連接 有序集合去重的代碼,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • Python自動(dòng)化運(yùn)維_文件內(nèi)容差異對(duì)比分析

    Python自動(dòng)化運(yùn)維_文件內(nèi)容差異對(duì)比分析

    下面小編就為大家分享一篇Python自動(dòng)化運(yùn)維_文件內(nèi)容差異對(duì)比分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12

最新評(píng)論

侯马市| 河源市| 万年县| 成都市| 新晃| 临湘市| 桐梓县| 宝兴县| 维西| 山阳县| 常山县| 东乌珠穆沁旗| 盐津县| 连山| 武功县| 清苑县| 睢宁县| 唐海县| 千阳县| 井陉县| 大城县| 民勤县| 昌宁县| 隆回县| 连南| 成武县| 布尔津县| 门头沟区| 且末县| 阿城市| 北京市| 宁阳县| 青龙| 乐陵市| 昂仁县| 韶关市| 隆德县| 通城县| 富平县| 伽师县| 绥棱县|