使用 functools 和不使用 functools 的装饰器之间的区别?
Difference between a decorator using functools and one without?
我有以下两个装饰器:
装饰器 1:
import functools
def overrides(interface_class):
print('interface_class:', interface_class.__name__)
def decorator(method):
print('method:', method.__name__)
@functools.wraps(method)
def func(*args, **kwargs):
assert (method.__name__ in dir(interface_class))
return method
return func
return decorator
装饰者 2:
def overrides(interface_class):
def overrider(method):
print('Method name:', method.__name__)
assert(method.__name__ in dir(interface_class))
return method
return overrider
对于装饰器1,我重写了一个例子,它使用了functools。 Decorator 2 我在 Whosebug 上找到了一个工作示例。每当我 运行 包含程序时,装饰器 1 不执行 assert 语句,而装饰器 2 执行。这两者有什么区别,是什么原因造成的?
编辑#1:
根据这个问题的答案、第一条评论和另一个例子,我重写了它,现在可以使用了:
def overrides(interface_class):
def my_decorator(method):
assert (method.__name__ in dir(interface_class)), \
'Trying to override a method named ' + \
method.__name__ + \
' in the interface ' + \
interface_class.__name__ + \
', which does not exist in the interface. Is this a method naming issue?'
@functools.wraps(method)
def wrapped(*args, **kwargs):
return method(*args, **kwargs)
return wrapped
return my_decorator
我将尝试用我自己的话来解释 assert
语句的位置:因为 assert
语句不是方法 "new functionality" 的一部分(实际上没有新功能,只有关于它的断言),它不属于函数 func
内部,而是属于函数外部。它只会执行一次,当方法被装饰时,这会发生,当程序启动时,因为那是应用函数装饰器的时候,而它会在每次调用装饰函数时执行,如果它是在那个装饰函数中。 运行 每次断言都是不可取的,因为它的性质。
– 这个解释还有错吗?
您的第一个装饰器尝试在调用方法时检查该方法是否是接口的一部分。第二个版本在装饰器为 运行 时进行检查(在方法定义时)。
您的第一个版本中存在错误,这可能会阻止您看到它的工作。最里面的函数返回 method
,当它应该调用它并返回结果时:return method(*args, **kwargs)
functools.wraps
函数在第一个装饰器中很有用,因为您要用包装器替换原始方法。 wraps
装饰器使包装函数的名称和文档字符串与包装函数的名称和文档字符串相匹配(这样 help
之类的东西就可以按预期工作)。第二个装饰器根本没有替换方法(装饰器 returns 如果未命中断言,它不会改变),因此没有包装函数需要 functools.wraps
的帮助。
我有以下两个装饰器:
装饰器 1:
import functools
def overrides(interface_class):
print('interface_class:', interface_class.__name__)
def decorator(method):
print('method:', method.__name__)
@functools.wraps(method)
def func(*args, **kwargs):
assert (method.__name__ in dir(interface_class))
return method
return func
return decorator
装饰者 2:
def overrides(interface_class):
def overrider(method):
print('Method name:', method.__name__)
assert(method.__name__ in dir(interface_class))
return method
return overrider
对于装饰器1,我重写了一个例子,它使用了functools。 Decorator 2 我在 Whosebug 上找到了一个工作示例。每当我 运行 包含程序时,装饰器 1 不执行 assert 语句,而装饰器 2 执行。这两者有什么区别,是什么原因造成的?
编辑#1:
根据这个问题的答案、第一条评论和另一个例子,我重写了它,现在可以使用了:
def overrides(interface_class):
def my_decorator(method):
assert (method.__name__ in dir(interface_class)), \
'Trying to override a method named ' + \
method.__name__ + \
' in the interface ' + \
interface_class.__name__ + \
', which does not exist in the interface. Is this a method naming issue?'
@functools.wraps(method)
def wrapped(*args, **kwargs):
return method(*args, **kwargs)
return wrapped
return my_decorator
我将尝试用我自己的话来解释 assert
语句的位置:因为 assert
语句不是方法 "new functionality" 的一部分(实际上没有新功能,只有关于它的断言),它不属于函数 func
内部,而是属于函数外部。它只会执行一次,当方法被装饰时,这会发生,当程序启动时,因为那是应用函数装饰器的时候,而它会在每次调用装饰函数时执行,如果它是在那个装饰函数中。 运行 每次断言都是不可取的,因为它的性质。
– 这个解释还有错吗?
您的第一个装饰器尝试在调用方法时检查该方法是否是接口的一部分。第二个版本在装饰器为 运行 时进行检查(在方法定义时)。
您的第一个版本中存在错误,这可能会阻止您看到它的工作。最里面的函数返回 method
,当它应该调用它并返回结果时:return method(*args, **kwargs)
functools.wraps
函数在第一个装饰器中很有用,因为您要用包装器替换原始方法。 wraps
装饰器使包装函数的名称和文档字符串与包装函数的名称和文档字符串相匹配(这样 help
之类的东西就可以按预期工作)。第二个装饰器根本没有替换方法(装饰器 returns 如果未命中断言,它不会改变),因此没有包装函数需要 functools.wraps
的帮助。