如何将装饰器附加到 python 中的函数 "after the fact"?
How can one attach a decorator to a function "after the fact" in python?
我对 python 中函数装饰器的理解(我可能是错的)是它们应该添加副作用并修改函数的 return 值。现在装饰器被添加到要装饰的函数的函数定义之上或通过赋值。这是一个小例子:
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()
装饰器来保留函数元数据,例如名称和文档字符串。
装饰 class 在这方面没有什么不同:
ClassName = decorator(ClassName)
关于Python 2、对于methods需要注意抓取原始未绑定函数;最简单的方法是使用 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 个版本。另一种方法是从 class __dict__
中获取函数对象以避免描述符协议启动:
ClassName.function_name = decorator(ClassName.__dict__['function_name'])
我对 python 中函数装饰器的理解(我可能是错的)是它们应该添加副作用并修改函数的 return 值。现在装饰器被添加到要装饰的函数的函数定义之上或通过赋值。这是一个小例子:
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()
装饰器来保留函数元数据,例如名称和文档字符串。
装饰 class 在这方面没有什么不同:
ClassName = decorator(ClassName)
关于Python 2、对于methods需要注意抓取原始未绑定函数;最简单的方法是使用 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 个版本。另一种方法是从 class __dict__
中获取函数对象以避免描述符协议启动:
ClassName.function_name = decorator(ClassName.__dict__['function_name'])