當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


Python Functools update_wrapper()用法及代碼示例


Python中的functools模塊處理高階函數,即在(作為參數)上操作或返回函數以及其他此類可調用對象的函數。 functools模塊提供了多種方法,例如cached_property(func), cmp_to_key(func), lru_cache(func), wraps(func)等等。值得注意的是,這些方法將函數作為參數。

在本文中,我們將討論該工具的目的和應用。update_wrapper()functools模塊提供的方法。此方法用於更新包裝函數的元數據,以反映包裝函數的元數據,從而提高可讀性和re-usability代碼。這update_wrapper()方法采用以下參數:

用法:@functools.update_wrapper(wrapper, wrapped, assigned = WRAPPER_ASSIGNMENTS, updated = WRAPPER_UPDATES)

參數:

  1. wrapper:包裝函數。
  2. wrapped:被包裝的函數或被包裝的函數。
  3. assigned:包裝函數的屬性以元組(可選參數)的形式分配給包裝函數的匹配屬性。
  4. updated:包裝函數的屬性相對於原始函數屬性(作為元組(可選參數))進行了更新。

為了更好地理解此方法,讓我們觀察一下在Python中使用裝飾器和局部函數的幾種情況。



範例1:

# Defining the decorator 
def hi(func):
  
    def wrapper():
        "Hi has taken over Hello Documentation"
        print("Hi geeks") 
        func() 
  
    return wrapper 
      
@hi
def hello():
  
    "this is the documentation of Hello Function"
    print("Hey Geeks") 
  
# Driver Code 
print(hello.__name__) 
print(hello.__doc__) 
help(hello)

輸出:

wrapper
Hi has taken over Hello Documentation
Help on function wrapper in module __main__:

wrapper()
    Hi has taken over Hello Documentation

在上麵的示例中,當我們使用裝飾器函數hi並使用其包裝器來包裝hello時,函數hello的模塊級常量(例如__name __,__ doc__等)將替換為函數hi中的包裝器。

當使用functools模塊中的局部函數時,也會出現相同的情況。讓我們來看一個例子:

範例2:

import functools 
  
  
def divide(a, b):
    "Original Documentation of Divide"
    return a / b 
  
half = functools.partial(divide, b = 2) 
oneThird = functools.partial(divide, b = 3) 
  
try:
    print(half.__name__) 
except AttributeError:
    print('No Name') 
print(half.__doc__)

輸出:

No Name
partial(func, *args, **keywords) - new function with partial application
of the given arguments and keywords.

在上麵的示例中,Half和oneThird沒有__name__(在引用時拋出AttributeError),因為它們是通過局部函數創建的。作為他們的文檔,他們繼承了partial方法的文檔。



上麵的情況從本質上來說是有問題的,因為模塊級常量用於標識,管理和檢索內容的重要目的。由於這些原因以及跟蹤內容的使用情況,元數據非常重要。因此,如果嘗試創建一個API或庫,它將不是user-friendly,因為help(function)不會返回有關如何使用其方法的有意義的信息。幫助(函數)將返回包裝函數的文檔,這會使用戶感到困惑。通過@ functools.update_wrapper()可以輕鬆解決此問題。

讓我們考慮第一個例子。我們可以通過以下方式使用update_wrapper():
範例1:

# Python program to demonstrate 
# ipdate)wrapper() method 
  
  
import functools as ft 
  
  
# Defining the decorator 
def hi(func):
      
    def wrapper():
        "Hi has taken over Hello Documentation"
        print("Hi geeks") 
        func() 
          
    # Note The following Steps Clearly 
    print("UPDATED WRAPPER DATA") 
    print(f'WRAPPER ASSIGNMENTS:{ft.WRAPPER_ASSIGNMENTS}') 
    print(f'UPDATES:{ft.WRAPPER_UPDATES}') 
      
    # Updating Metadata of wrapper  
    # using update_wrapper 
    ft.update_wrapper(wrapper, func) 
    return wrapper 
      
@hi
def hello():
    "this is the documentation of Hello Function"
    print("Hey Geeks") 
  
print(hello.__name__) 
print(hello.__doc__) 
help(hello)

輸出:

UPDATED WRAPPER DATA
WRAPPER ASSIGNMENTS:(‘__module__’, ‘__name__’, ‘__qualname__’, ‘__doc__’, ‘__annotations__’)
UPDATES:(‘__dict__’, )
hello
this is the documentation of Hello Function
Help on function hello in module __main__:

hello()
this is the documentation of Hello Function

通過使用update_wrapper(),我們看到函數hello保留了其原始元數據。同樣,讓我們​​檢查第二個示例,但是這次我們將使用update_wrapper()

# Python program to demonstrate 
# ipdate)wrapper() method 
  
  
import functools 
  
  
def divide(a, b):
    "Original Documentation of Divide"
    return a / b 
  
half = functools.partial(divide,  
                         b = 2) 
  
oneThird = functools.partial(divide,  
                             b = 3) 
  
print("UPDATED WRAPPER DATA") 
print(f'WRAPPER ASSIGNMENTS:{functools.WRAPPER_ASSIGNMENTS}') 
print(f'UPDATES:{functools.WRAPPER_UPDATES}') 
  
# Updating Metadata of wrapper 
# using update_wrapper 
ft.update_wrapper(half, divide) 
  
try:
    print(half.__name__) 
      
except AttributeError:
    print('No Name') 
      
print(half.__doc__) 
  
help(half) 
help(oneThird)

輸出:

UPDATED WRAPPER DATA
WRAPPER ASSIGNMENTS:(‘__module__’, ‘__name__’, ‘__qualname__’, ‘__doc__’, ‘__annotations__’)
UPDATES:(‘__dict__’,)
divide
Original Documentation of Divide
Help on partial in module __main__ object:

divide = class partial(builtins.object)
| partial(func, *args, **keywords) - new function with partial application
| of the given arguments and keywords.
|
| Methods defined here:
|
| __call__(self, /, *args, **kwargs)
| Call self as a function.
|
| __delattr__(self, name, /)
| Implement delattr(self, name).
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| __reduce__(…)
| helper for pickle
|
| __repr__(self, /)
| Return repr(self).
|
| __setattr__(self, name, value, /)
| Implement setattr(self, name, value).
|
| __setstate__(…)
|
| ———————————————————————-
| Data descriptors defined here:
|
| __dict__
|
| args
| tuple of arguments to future partial calls
|
| func
| function object to use in future partial calls
|
| keywords
| dictionary of keyword arguments to future partial calls

Help on partial object:

class partial(builtins.object)
| partial(func, *args, **keywords) - new function with partial application
| of the given arguments and keywords.
|
| Methods defined here:
|
| __call__(self, /, *args, **kwargs)
| Call self as a function.
|
| __delattr__(self, name, /)
| Implement delattr(self, name).
|
| __getattribute__(self, name, /)
| Return getattr(self, name).
|
| __new__(*args, **kwargs) from builtins.type
| Create and return a new object. See help(type) for accurate signature.
|
| __reduce__(…)
| helper for pickle
|
| __repr__(self, /)
| Return repr(self).
|
| __setattr__(self, name, value, /)
| Implement setattr(self, name, value).
|
| __setstate__(…)
|
| ———————————————————————-
| Data descriptors defined here:
|
| __dict__
|
| args
| tuple of arguments to future partial calls
|
| func
| function object to use in future partial calls
|
| keywords
| dictionary of keyword arguments to future partial calls

在此示例中,我們看到一半繼承了函數除法的基本module-level常量。當我們使用help(half)時,我們看到它部分地來自除法。值得注意的是,oneThird並非如此,因為help(oneThird)不會告訴我們父函數。

因此,通過以上說明,我們可以了解functools模塊中提供的update_wrapper(…)方法的用例。為了保留函數的元數據以供進一步使用,update_wrapper(…)是一種函數強大的工具,可以輕鬆使用。因此,該方法在裝飾器和局部裝飾的情況下被證明非常有用。

相關用法


注:本文由純淨天空篩選整理自tirtharajsengupta大神的英文原創作品 Python Functools – update_wrapper()。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。