一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Python編程中非常重要卻又被嚴重低估的庫decorator

Python編程中非常重要卻又被嚴重低估的庫decorator

2022-02-17 13:28寫代碼的明哥 Python

今天介紹的是一個已經存在十年,但是依舊不紅的庫 decorator,好像很少有人知道他的存在一樣。本篇文章不會過多的向你介紹裝飾器的基本知識,我會默認你知道什么是裝飾器,并且懂得如何寫一個簡單的裝飾器

本文已經收錄于《Python黑魔法手冊》v2.1 版本,在線文檔請前往

Python黑魔法手冊 2.0 文檔 

這個庫可以幫你做什么呢 ?

其實很簡單,就是可以幫你更方便地寫python裝飾器代碼,更重要的是,它讓 Python 中被裝飾器裝飾后的方法長得更像裝飾前的方法。

不了解裝飾器的可以先去閱讀服務器之家之前的文章,非常全且詳細的介紹了裝飾器的各種實現方法。

常規的裝飾器

下面這是一個最簡單的裝飾器示例,在運行 myfunc 函數的前后都會打印一條日志。

?
1
2
3
4
5
6
7
8
9
10
11
12
def deco(func):
    def wrapper(*args, **kw):
        print("Ready to run task")
        func(*args, **kw)
        print("Successful to run task")
    return wrapper
 
@deco
def myfunc():
    print("Running the task")
 
myfunc()

裝飾器使用起來,似乎有些高端和魔幻,對于一些重復性的功能,往往我們會封裝成一個裝飾器函數。

在定義一個裝飾器的時候,我們都需要像上面一樣機械性的寫一個嵌套的函數,對裝飾器原理理解不深的初學者,往往過段時間就會忘記如何定義裝飾器。

有一些比較聰明的同學,會利用 PyCharm 來自動生成裝飾器模板

Python編程中非常重要卻又被嚴重低估的庫decorator

然后要使用的時候,直接敲入 deco 就會生成一個簡單的生成器代碼,提高編碼的準備效率

Python編程中非常重要卻又被嚴重低估的庫decorator

使用神庫

使用 PyCharm 的 Live Template ,雖然能降低編寫裝飾器的難度,但卻要依賴 PyCharm 這一專業的代碼編輯器。

這里,明哥要教你一個更加簡單的方法,使用這個方法呢,你需要先安裝一個庫 : decorator,使用 pip 可以很輕易地去安裝它

?
1
$ python3 -m pip install decorator

從庫的名稱不難看出,這是一個專門用來解決裝飾器問題的第三方庫。

有了它之后,你會驚奇的發現,以后自己定義的裝飾器,就再也不需要寫嵌套的函數了

?
1
2
3
4
5
6
7
8
9
10
11
12
13
from decorator import decorator
 
@decorator
def deco(func, *args, **kw):
    print("Ready to run task")
    func(*args, **kw)
    print("Successful to run task")
 
@deco
def myfunc():
    print("Running the task")
 
myfunc()

deco 作為裝飾函數,第一個參數是固定的,都是指被裝飾函數,而后面的參數都固定使用 可變參數 *args**kw 的寫法,代碼被裝飾函數的原參數。

這種寫法,不得不說,更加符合直覺,代碼的邏輯也更容易理解。

帶參數的裝飾器

裝飾器根據有沒有攜帶參數,可以分為兩種

第一種:不帶參數,最簡單的示例,上面已經舉例

?
1
2
3
4
def decorator(func):
    def wrapper(*args, **kw):
        func(*args, **kw)
    return wrapper

第二種:帶參數,這就相對復雜了,理解起來了也不是那么容易。

?
1
2
3
4
5
6
def decorator(arg1, arg2):
    def wrapper(func):
        def deco(*args, **kwargs)
            func(*args, **kwargs)
        return deco
    return wrapper

那么對于需要帶參數的裝飾器,decorator 是否也一樣能很好的支持呢?

下面是一個官方的示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from decorator import decorator
 
@decorator
def warn_slow(func, timelimit=60, *args, **kw):
    t0 = time.time()
    result = func(*args, **kw)
    dt = time.time() - t0
    if dt > timelimit:
        logging.warn('%s took %d seconds', func.__name__, dt)
    else:
        logging.info('%s took %d seconds', func.__name__, dt)
    return result
  
@warn_slow(timelimit=600# warn if it takes more than 10 minutes
def run_calculation(tempdir, outdir):
    pass

可以看到

  • 裝飾函數的第一個參數,還是被裝飾器 func ,這個跟之前一樣
  • 而第二個參數 timelimit 寫成了位置參數的寫法,并且有默認值
  • 再往后,就還是跟原來一樣使用了可變參數的寫法

不難推斷,只要你在裝飾函數中第二個參數開始,使用了非可變參數的寫法,這些參數就可以做為裝飾器調用時的參數。

簽名問題有解決?

我們在自己寫裝飾器的時候,通常都會順手加上一個叫 functools.wraps 的裝飾器,我想你應該也經常見過,那他有啥用呢?

先來看一個例子

?
1
2
3
4
5
6
7
8
9
10
11
def wrapper(func):
    def inner_function():
        pass
    return inner_function
 
@wrapper
def wrapped():
    pass
 
print(wrapped.__name__)
#inner_function

為什么會這樣子?不是應該返回 func 嗎?

這也不難理解,因為上邊執行func 和下邊 decorator(func) 是等價的,所以上面 func.__name__ 是等價于下面decorator(func).__name__ 的,那當然名字是 inner_function

?
1
2
3
4
5
6
7
8
9
10
def wrapper(func):
    def inner_function():
        pass
    return inner_function
 
def wrapped():
    pass
 
print(wrapper(wrapped).__name__)
#inner_function

目前,我們可以看到當一個函數被裝飾器裝飾過后,它的簽名信息會發生變化(譬如上面看到的函數名)

那如何避免這種情況的產生?

解決方案就是使用我們前面所說的 functools .wraps 裝飾器。

它的作用就是將 被修飾的函數(wrapped) 的一些屬性值賦值給 修飾器函數(wrapper) ,最終讓屬性的顯示更符合我們的直覺。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from functools import wraps
 
def wrapper(func):
    @wraps(func)
    def inner_function():
        pass
    return inner_function
 
@wrapper
def wrapped():
    pass
 
print(wrapped.__name__)
# wrapped

那么問題就來了,我們使用了 decorator 之后,是否還會存在這種簽名的問題呢?

寫個例子來驗證一下就知道啦

?
1
2
3
4
5
6
7
8
9
10
11
12
13
from decorator import decorator
 
@decorator
def deco(func, *args, **kw):
    print("Ready to run task")
    func(*args, **kw)
    print("Successful to run task")
 
@deco
def myfunc():
    print("Running the task")
 
print(myfunc.__name__)

輸出的結果是 myfunc,說明 decorator 已經默認幫我們處理了一切可預見的問題。

總結一下

decorator 是一個提高裝飾器編碼效率的第三方庫,它適用于對裝飾器原理感到困惑的新手,可以讓你很輕易的寫出更符合人類直覺的代碼。對于帶參數裝飾器的定義,是非常復雜的,它需要要寫多層的嵌套函數,并且需要你熟悉各個參數的傳遞路徑,才能保證你寫出來的裝飾器可以正常使用。這時候,只要用上 decorator 這個庫,你就可以很輕松的寫出一個帶參數的裝飾器。同時你也不用擔心他會出現簽名問題,這些它都為你妥善的處理好了。

這么棒的一個庫,推薦你使用起來。

以上就是Python編程中非常重要卻又被嚴重低估的庫decorator的詳細內容,更多關于Python編程庫decorator的資料請關注服務器之家其它相關文章!

原文鏈接:https://blog.csdn.net/weixin_36338224/article/details/115946648

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: gav男人天堂 | 欧美 变态 另类 人妖班 | 欧美日韩国产亚洲一区二区 | 欧美贵妇vs高跟办公室 | 亚洲美洲国产日产 | 国产裸舞福利资源在线视频 | a天堂在线视频 | 艾秋麻豆果冻传媒老狼仙踪林 | 吃大胸寡妇的奶 | 国产一区二区精品久久 | а天堂中文最新版在线官网视频 | 456亚洲人成高清在线 | 大陆国产vs国产对白 | 亚洲午夜精品久久久久久人妖 | bt天堂在线观看国产 | 美女的隐私视频免费看软件 | 我与肥熟老妇的性事 | 日本伦理动漫在线观看 | 亚洲成人77777 | 短篇同学新婚h系列小说 | 国产成人综合亚洲亚洲欧美 | 俄罗斯三级完整版在线观看 | 扒开黑女人p大荫蒂老女人 扒开大腿狠狠挺进视频 | 欧洲一级黑寡妇 | 国产精品久久久久久久午夜片 | 99视频网址 | japanese在线看 | 猥琐对着美女飞机喷到脸上 | 麻豆视频免费在线观看 | 我强进了老师身体在线观看 | 2020年精品国产午夜福利在线 | 亚洲精品无码久久不卡 | 国色天香 社区视频 | 成年人免费观看的视频 | 亚洲精品一区二区久久久久 | 日本高清免费中文字幕不卡 | 日韩一区三区 | 欧美激情精品久久久久久不卡 | 我和老丈洗澡同性 | 91高跟丝袜| 国产福利兔女郎在线观看 |