理解python的decorator中的函数包装器

理解python的decorator中的函数包装器,python,decorator,wrapper,Python,Decorator,Wrapper,我有两个python装饰器实现的示例。我想知道它们在函数包装器实现方面有什么不同。他们的工作方式一样吗?有什么背景差异吗?做函数包装器的pythonic方法是什么 例1 例2 首先,我们正在寻找一种比装饰师更复杂的东西。decorator是一个函数,它接受一个函数作为输入并返回一个函数。在这里,顶级函数返回decorators。因此,它们实际上也是上述意义上的装饰器,即使通常所称的装饰器是第一个内部函数。此定义方案通常用于创建参数化装饰器 这样看来,您是在专门询问functools.wrapps

我有两个python装饰器实现的示例。我想知道它们在函数包装器实现方面有什么不同。他们的工作方式一样吗?有什么背景差异吗?做函数包装器的pythonic方法是什么

例1

例2


首先,我们正在寻找一种比装饰师更复杂的东西。decorator是一个函数,它接受一个函数作为输入并返回一个函数。在这里,顶级函数返回decorators。因此,它们实际上也是上述意义上的装饰器,即使通常所称的装饰器是第一个内部函数。此定义方案通常用于创建参数化装饰器

这样看来,您是在专门询问functools.wrapps。如果是这样的话,我只能敦促你看看医生


基本上,它用于使装饰器返回的函数看起来与装饰的函数相同,即:具有相同的名称、docstring等。

您在问什么?这个装饰器使它成为可用的关于包装函数的信息,而不是关于包装器的信息。但是使用它真的是必要的吗?第二个例子没有使用它,并且可以工作。您可以编写没有它的decorator,但是它们往往会使获取包装函数的数据变得困难。因此,如果您想读取包装函数的docstring,或者知道它的名称等,如果不使用包装,这是非常困难的。这被认为是良好的实践:您可能永远不需要该功能,但您永远不知道,如果您提供这些装饰器供其他人使用,他们可能需要它。它也不会伤害任何东西。我想不出使用wrapsIt有什么坏处,它不需要让代码正常工作,同样,注释、文档和良好的编码风格也不需要。functools.wrapps复制函数的名称、docstring和其他内容,这使其他人更容易使用修饰过的函数,并允许您访问未修饰过的函数。没有理由不使用它。感谢Aran和Patrick,我将修改代码中的第二个示例以使用@wrapps:谢谢你,阿尼斯,我去看看。因此,出于您指出的这些原因,更倾向于使用@wrapps,对吗?
from functools import wraps

def retry(times=3, waiting_time=30):
    '''
    Decorator to retry any functions 'times' times.

    Parameters
    ----------    
    times: int
        Number of times to retry to execute
    waiting_time: int
        Number of times to wait between retries

    '''
    def retry_decorator(func):
        # My doubt is here.
        @wraps(func)
        def retried_function(*args, **kwargs):
            for i in range(times):
                try:                           
                    return func(*args, **kwargs)
                except Exception as err:
                    print(f'Try nº {i+1}')
                    sleep(waiting_time)           

            func(*args, **kwargs)

        return retried_function

    return retry_decorator
def exception(logger):
    '''
    Decorator that wraps the passed function and logs 
    exceptions when it occurs.

    Parameters
    ----------
    logger : logging object
        Object to use to log exceptions

    ''' 
    def decorator(func):
        # Here the function wrapper is different from example 1     
        def wrapper(*args, **kwargs):
            try:
                return func(*args, **kwargs)
            except:
                # log the exception
                err = "There was an exception in "
                err += func.__name__
                logger.exception(err) 
                # re-raise the exception
                raise
        return wrapper
    return decorator