问题描述
我理解python中的函数装饰器的方式(我可能错了),是因为它们应该增加副作用并修改函数的返回值。现在,将装饰器添加到要装饰的功能的函数定义上方或通过分配。这是一个小例子:
The way I understand decorators of function in python (and I might be wrong), is that they are supposed to add side effects and modify the return value of a function. Now decorators are added above the function definition of the function to be decorated or by an assignment. Here is a small example:
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的math模块导入 sqrt()
函数,并想对其进行修饰,我该如何处理?
Now, how does one attach a decorator to a function defined elsewhere, ideally retaining the original function's name and docstring (like functools.wraps
does)? For example, I'm importing the sqrt()
function from Python's math module, and want to decorate it, how do I go about that?
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
事后在类中装饰方法怎么样?如何自己装饰类?
How about decorate methods within classes after the fact? How about decorating classes themselves?
推荐答案
您将 sqrt
导入到模块中,只需在自己的全局命名空间中将装饰器应用到那里即可:
You imported sqrt
into your module, just apply the decorator there in your own global namespace:
sqrt = print_args_decor(sqrt)
这会将模块命名空间中的名称 sqrt
设置为装饰器的结果。不需要在此模块中最初定义 sqrt
。
This sets the name sqrt
in your module namespace to the result of the decorator. There is no requirement that sqrt
was originally defined in this module.
由装饰器使用 functools.wraps()
装饰器可以保留函数元数据,例如名称和文档字符串。
It is up to the decorator to uses the functools.wraps()
decorator to preserve function metadata such as the name and docstring.
装饰类不是在这方面有所不同:
Decorating a class is no different in this respect:
ClassName = decorator(ClassName)
在Python 2上,对于方法,您需要格外小心,以获取原始的未绑定函数;最简单的方法是使用方法。__func __
属性:
On Python 2, for methods you need to be careful to grab the original unbound function; easiest is to use the method.__func__
attribute:
try:
# Python 2
ClassName.function_name = decorator(ClassName.function_name.__func__)
except AttributeError:
# Python 3
ClassName.function_name = decorator(ClassName.function_name)
我已将以上内容打包为尝试...除外
可以使模式在Python版本之间工作。另一种选择是从类 __ dict __
中获取函数对象,以避免插入描述符协议:
I've wrapped the above in a try...except
to make the pattern work across Python versions. The alternative is to grab the function object out of the class __dict__
to avoid the descriptor protocol from kicking in:
ClassName.function_name = decorator(ClassName.__dict__['function_name'])
这篇关于如何将装饰器附加到“事后”功能中?在python中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!