当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


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()。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。