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)
参数:
- wrapper:包装函数。
- wrapped:被包装的函数或被包装的函数。
- assigned:包装函数的属性以元组(可选参数)的形式分配给包装函数的匹配属性。
- 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 callsHelp 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(…)是一种函数强大的工具,可以轻松使用。因此,该方法在装饰器和局部装饰的情况下被证明非常有用。
相关用法
- Python functools.wraps()用法及代码示例
- Python Functools total_ordering()用法及代码示例
- Python Functools lru_cache()用法及代码示例
- Python Functools cached_property()用法及代码示例
注:本文由纯净天空筛选整理自tirtharajsengupta大神的英文原创作品 Python Functools – update_wrapper()。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。