如何创建使用`functools.wraps`并保留对装饰实例的访问权时接受参数的装饰器类

时间:2019-09-06 18:09:04

标签: python decorator python-decorators

1。我的要求

  1. 装饰器类应该使用functools.wraps,以便其具有适当的自省和组织功能,以备后用。
  2. 应该可以访问装饰的实例。
    • 在下面的示例中,我通过将wrapped_self参数传递给__call__方法来实现这一目的。
  3. 如标题所述,装饰器类必须具有可针对每种方法进行调整的参数。

2。看起来像一个例子

理想情况应如下所示:

class A():

    def __init__(self):
        ...

    @LoggerDecorator(logger_name='test.log')
    def do_something(self):
        ...
到目前为止,

装饰器类是(基于David Beazley's Python Cookbook的配方的基本记录器装饰器):

class LoggerDecorator():

    def __init__(self, func, logger_name):
        wraps(func)(self)
        self.logger_name = logger_name

    def config_logger(self):
        ... # for example, uses `self.logger_name` to configure the decorator

    def __call__(self, wrapped_self, *args, **kwargs):
        self.config_logger()
        wrapped_self.logger = self.logger
        func_to_return = self.__wrapped__(wrapped_self, *args, **kwargs)
        return func_to_return

    def __get__(self, instance, cls):
        if instance is None:
            return self
        else:
            return types.MethodType(self, instance)

3。我该如何解决?

我遇到的错误是指__init__显然没有识别出第三个参数:

TypeError: __init__() missing 1 required positional argument: 'func'

有人建议我将func放在__call__方法中。但是,如果我将它放在那里作为参数,则wrapped_self不能正确地作为参数读取,并且会出现此错误:

__call__() missing 1 required positional argument: 'wrapped_self'

我已经尝试了许多方法来解决此问题,包括:将wraps(func)(self)放在__call__内;以及this very close but not quite filling all of the requirements solution的许多变体(问题是我似乎无法再访问wrapped_self)。

2 个答案:

答案 0 :(得分:3)

由于您正在实现带有参数的装饰器,因此__init__的{​​{1}}方法应仅采用配置装饰器的参数,而LoggerDecorator方法应变为实际的装饰器,返回包装函数:

__call__

答案 1 :(得分:0)

from functools import wraps


class LoggerDecorator:

    def __init__(self, logger):
        self.logger = logger

    def __call__(self, func, *args, **kwargs):
        print func, args, kwargs
        # do processing
        return func

@LoggerDecorator('lala')
def a():
    print 1

以上内容应该可以正常工作。如果您打算使用关键字参数来调用装饰器,则可以从logger中删除__init__并使用**kwargs,这将返回所传递的键盘参数的字典。