我有以下两个装饰器:
装饰者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的例子。装饰器2我在Stackoverflow上找到了一个工作示例。每当我运行包含程序时,装饰器1不执行断言语句,而装饰器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
语句不是该方法的“新功能”的一部分(实际上没有新功能,但只有关于它的断言),它不属于函数func
的内部,而是属于它的外部。当程序启动时,它只会被执行一次,当程序被启动时会发生,因为这是应用函数装饰器时的时间,而每次调用装饰函数时都会执行它,如果它是在那个装饰的功能。由于其性质,每次运行断言都是不可取的。
- 这个解释中是否还有错误?
答案 0 :(得分:1)
当调用方法时,您的第一个装饰器会尝试检查该方法是否为接口的一部分。第二个版本在装饰器运行时进行检查(在方法定义时)。
您的第一个版本中存在错误,这可能会阻止您看到它的工作。最内部的函数返回method
,当它应该调用它并返回结果时:return method(*args, **kwargs)
functools.wraps
函数在第一个装饰器中很有用,因为您要用包装器替换原始方法。 wraps
装饰器使得包装函数的名称和文档字符串与包装函数的名称和文档字符串相匹配(因此像help
这样的东西按预期工作)。第二个装饰器根本不替换该方法(如果没有命中断言,装饰器将返回它不变),因此没有需要functools.wraps
帮助的包装函数。