gpt4 book ai didi

python - 如何将装饰器附加到 python 中的函数 "after the fact"?

转载 作者:太空狗 更新时间:2023-10-29 19:37:23 25 4
gpt4 key购买 nike

我对 python 中函数装饰器的理解(我可能是错的)是它们应该添加副作用并修改函数的返回值。现在装饰器被添加到要装饰的函数的函数定义之上或通过赋值。这是一个小例子:

def print_args_decor(function):
def wrapper(*args, **kwargs):
print 'Arguments:', args, kwargs # Added side-effect
return function(*args, **kwargs)*5 # Modified return value
return wrapper

@print_args_decor
def do_stuff(strg, n=10):
"""Repeats strg a few times."""
return strg * n

new_decorated_func = print_args_decor(do_stuff) # Decoration by assignment

print do_stuff('a', 2) # Output: aaaaaaaaaa

现在,如何将装饰器附加到别处定义的函数,理想情况下保留原始函数的名称和文档字符串(如functools.wraps 是)?例如,我正在从 Python 的数学模块中导入 sqrt() 函数,并想装饰它,我该怎么做?

from functools import wraps
from math import sqrt

def print_args_decor(function):
@wraps(function)
def wrapper(*args, **kwargs):
print 'Arguments:', args, kwargs # Added side-effect
return function(*args, **kwargs)*5 # Modified return value
return wrapper

# Decorate the sqrt() function from math module somehow
@print_args_decor #???
sqrt #???

print sqrt(9)
# Output:
# Arguments: ([9],) {}
# 15 # <--- sqrt(9)*5

事后装饰类中的方法怎么样?自己装饰类怎么样?

最佳答案

您将 sqrt 导入到您的模块中,只需在您自己的全局命名空间中应用装饰器即可:

sqrt = print_args_decor(sqrt)

这会将模块命名空间中的名称 sqrt 设置为装饰器的结果。不要求 sqrt 最初是在此模块中定义的。

由装饰器使用 functools.wraps() 装饰器来保留函数元数据,例如名称和文档字符串。

装饰类在这方面没有什么不同:

ClassName = decorator(ClassName)

在 Python 2 上,对于方法,您需要小心获取原始未绑定(bind)的函数;最简单的方法是使用 method.__func__ 属性:

try:
# Python 2
ClassName.function_name = decorator(ClassName.function_name.__func__)
except AttributeError:
# Python 3
ClassName.function_name = decorator(ClassName.function_name)

我将上面的内容包装在 try...except 中,以使该模式适用于 Python 版本。另一种方法是从类 __dict__ 中获取函数对象以避免描述符协议(protocol)启动:

ClassName.function_name = decorator(ClassName.__dict__['function_name'])

关于python - 如何将装饰器附加到 python 中的函数 "after the fact"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33868886/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com