簡體   English   中英

為什么裝飾器函數有返回值?

[英]Why does a decorator function have a return value?

考慮以下示例。

def decorator(function_to_decorate):
    def wrapper():
        print('Entering', function_to_decorate.__name__)
        function_to_decorate()
        print('Exiting', function_to_decorate.__name__)
    return wrapper

@decorator
def func():
    print("Original function.")

func()

因為@decorator語法只是func = my_decorator(func)的簡寫,所以my_decorator必須返回一些東西是合乎邏輯的。 我的問題是:為什么以這種方式定義裝飾器而不是沒有返回值: my_decorator(func) 返回包裝函數wrapper的目的是什么?


編輯

裝飾器如何做不僅僅是一個簡單的包裝器?

def wrapper(function_to_decorate):
    print('Entering', function_to_decorate.__name__)
    function_to_decorate()
    print('Exiting', function_to_decorate.__name__)
def func():
    print("Original function.")
wrapper(func)

想象一下,如果您可以將裝飾器應用於常規變量賦值,如下所示:

def add1(x):
    return x + 1

@add1
number = 5

函數裝飾器的類似行為是這樣的:

number = 5
number = add1(number)

這將導致將值6分配給變量number 現在想象一下,裝飾器只是被調用而沒有返回任何東西:

number = 5
add1(number)

這段代碼不可能將6賦給變量number ,因為number按值傳遞的,而不是按引用傳遞 在 Python 中,函數不能為它無法訪問的完全不同范圍內的變量分配新值。


def語句實際上是一種賦值; 它將函數分配給您定義它的名稱。 例如,函數定義def func(): pass編譯為執行STORE_NAME字節碼,即賦值:

  1     0 LOAD_CONST         0 (<code object func at ...>)
        3 LOAD_CONST         1 ('func')
        6 MAKE_FUNCTION      0
        9 STORE_NAME         0 (func)

因此,出於同樣的原因,函數裝飾器的行為與上述相同; 裝飾器函數不能在完全不同的范圍內將新函數重新分配給變量func ,因為func是按值傳遞給裝飾器的,而不是通過引用。

func = decorator(func)等價實際上有點誤導。 完全正確,當您使用裝飾器時,您在def語句中定義的函數將直接傳遞給裝飾器,而不是在傳遞之前分配給本地名稱func 這是字節碼:

  1     0 LOAD_NAME          0 (decorate)
        3 LOAD_CONST         0 (<code object func at ...>)
        6 LOAD_CONST         1 ('func')
        9 MAKE_FUNCTION      0
       12 CALL_FUNCTION      1 (1 positional, 0 keyword pair)
       15 STORE_NAME         1 (func)

一步步:

  • decorate函數被加載到堆棧中,
  • func的代碼對象被加載到堆棧上,然后是字符串'func' ,然后MAKE_FUNCTION指令將這兩個變成一個留在堆棧上的函數。
  • CALL_FUNCTION指令使用一個參數調用decorate函數(仍在堆棧中),即func函數。
  • 無論decorate函數返回什么,都會留在堆棧中,並由STORE_NAME指令分配給名稱func

因此,如果decorator函數沒有返回任何內容,那么將沒有任何東西可以分配給名稱func - 甚至不是def語句中的原始函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM