使用 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 的帮助。