簡體   English   中英

試圖了解 Python 包裝器

[英]Trying to understand a Python wrapper

對於下面的 function,我試圖理解

一世。 為什么wrapper.count = 0在包裝器 function 下方初始化? 為什么不在 def counter(func) 下面初始化? 為什么 wrapper.count 不將wrapper.count重置為 0,因為它運行在包裝器 function 之下?

我試圖了解什么是wrapper.count 為什么不初始化一個普通變量count而不是wrapper.count

def counter(func):
  def wrapper(*args, **kwargs):
    wrapper.count += 1
    # Call the function being decorated and return the result
    return func
  wrapper.count = 0
  # Return the new decorated function
  return wrapper

# Decorate foo() with the counter() decorator
@counter
def foo():
  print('calling foo()')

裝飾器出現錯誤,在包裝器 function 內,您需要:

return func(*args, **kwargs)  # instead of `return func`

為什么wrapper.count = 0在包裝器 function 下方初始化?

因為如果您在 wrapper function 內部執行此操作,那么它將始終將wrapper.count的值重置為0 除非您檢查它是否尚未定義。 (我在答案的最后給出了一個例子。)

為什么不在def counter(func)下面初始化?

因為包裝器 function 沒有在那里定義。 所以口譯員會抱怨它。

為什么wrapper.count不將wrapper.count重置為0 ,因為它是在包裝器 function 之下執行的?

因為當你用@counter裝飾器包裝一個 function 時,這個語句只執行一次,而且它不會在你每次調用foo() function 時執行。

我試圖了解什么是wrapper.count

這是一個 function 屬性。 或多或少類似於 C++ 等函數內部的static變量。

為什么不初始化一個普通變量count而不是wrapper.count

因為那將是一個局部變量,它會在每次調用時將count重置為 0。


還有另一種方法可以在包裝器 function 中定義wrapper.count = 0 所以現在你不需要在wrapper function 之外定義它。

def counter(func):
  def wrapper(*args, **kwargs):
    if not hasattr(wrapper, 'count'):
        wrapper.count = 0
    wrapper.count += 1
    return func(*args, **kwargs)
  return wrapper

在高層次上,裝飾的 function 維護一個計數器,記錄它被調用的次數。

代碼存在一個主要問題。 包裝器實際上並未按應有的方式調用包裝的 function。 而不是return func ,它只返回 function object,它應該是

return func(*args, **kwargs)

正如@warvariuc 指出的那樣,一個可能的原因是作者沒有或不知道nonlocal ,它可以讓您訪問封閉的命名空間。

我認為一個更合理的原因是您希望能夠訪問櫃台。 函數是具有可變字典的一流對象。 您可以分配和訪問它們的任意屬性。 幾次調用后檢查foo.count可能會很方便,否則為什么要首先維護它?

wrapper.counter以這種方式初始化的原因僅僅是在def語句運行以創建它之前,本地命名空間中不存在wrapper 每次運行counter時,內部def都會生成一個新的 function object 。 def通常是每次運行時創建 function object 的分配。

關於您顯示的代碼的另一個小問題是foo.__name__在裝飾之后將是wrapper而不是foo 為了緩解這種情況,並使其更忠實地模仿原始 function,您可以使用functools.wraps ,它是裝飾器包裝器的裝飾器。 您的代碼如下所示:

from functools import wraps

def counter(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        wrapper.count += 1
        # Call the function being decorated and return the result
        return func(*args, **kwargs)
    wrapper.count = 0
    # Return the new decorated function
    return wrapper

# Decorate foo() with the counter() decorator
@counter
def foo():
    print('calling foo()')

現在你可以做

>>> foo.__name__
'foo'
>>> foo()
calling foo()
>>> foo()
calling foo()
>>> foo()
calling foo()
>>> foo.count
3

為什么不初始化一個正常的變量計數而不是variable.count

我的猜測是這種模式首先出現在nonlocal 2 中,其中 nonlocal 語句不可用。 在我看來,該片段的作者只是試圖模擬 static 變量,例如 C 語言( https://stackoverflow.com/296/7

因為如果您嘗試使用在 function counter的頂層聲明的普通變量,您將無法在wrapper中分配給它。

如果您將count放在counter下方,您將使其成為全局變量,因此它將在裝飾器的所有實例之間共享,這可能不是所需的行為:

count = 0

def counter(func):

  def wrapper(*args, **kwargs):
    global count
    count += 1
    return func(*args, **kwargs)

  return wrapper

@counter
def foo():
  print('calling foo()')

這是一個nonlocal版本(Python 3+):

def counter(func):

  def wrapper(*args, **kwargs):
    nonlocal count
    count += 1
    # Call the function being decorated and return the result
    return func(*args, **kwargs)

  count = 0
  # Return the new decorated function
  return wrapper

# Decorate foo() with the counter() decorator
@counter
def foo():
  print('calling foo()')

暫無
暫無

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

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