简体   繁体   English

在类中声明装饰器

[英]Declaring decorator inside a class

I'm trying to use custom wrappers/decorators in Python, and I'd like to declare one inside a class, so that I could for instance print a snapshot of the attributes.我正在尝试在 Python 中使用自定义包装器/装饰器,并且我想一个类中声明一个,以便我可以打印属性的快照。 I've tried things from this question with no success.我已经尝试过这个问题,但没有成功。


Here is what I'd like to do (NB: this code doesn't work, I explain what happens below)这是我想要做的(注意:这段代码不起作用,我解释了下面会发生什么)

class TestWrapper():
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.c = 0

    def enter_exit_info(self, func):
        def wrapper(*arg, **kw):
            print '-- entering', func.__name__
            print '-- ', self.__dict__
            res = func(*arg, **kw)
            print '-- exiting', func.__name__
            print '-- ', self.__dict__
            return res
        return wrapper

    @enter_exit_info
    def add_in_c(self):
        self.c = self.a + self.b
        print self.c

    @enter_exit_info
    def mult_in_c(self):
        self.c = self.a * self.b
        print self.c


if __name__ == '__main__':
    t = TestWrapper(2, 3)
    t.add_in_c()
    t.mult_in_c()

The expected output is :预期的输出是:

-- entering add_in_c
-- {'a': 2, 'b': 3, 'c': 0}
5
-- exiting add_in_c
-- {'a': 2, 'b': 3, 'c': 5}
-- entering mult_in_c
-- {'a': 2, 'b': 3, 'c': 5}
6
-- exiting mult_in_c
-- {'a': 2, 'b': 3, 'c': 6}

But I this code gives但我这段代码给出了

Traceback (most recent call last):
  File "C:\Users\cccvag\workspace\Test\src\module2.py", line 2, in <module>
    class TestWrapper():
  File "C:\Users\cccvag\workspace\Test\src\module2.py", line 18, in     TestWrapper
    @enter_exit_info
TypeError: enter_exit_info() takes exactly 2 arguments (1 given)

And if I try @enter_exit_info(self) or @self.enter_exit_info , I get a NameError .如果我尝试@enter_exit_info(self)@self.enter_exit_info ,我会收到NameError What could I do?我能做什么?


EDIT:编辑:

I do not need above all to have the decorator physically declared inside the class, as long as it is able to access attributes from an instance of this class.我不需要首先在类中物理声明装饰器,只要它能够从此类的实例访问属性即可。 I thought it could only be made by declaring it inside the class, Rawing's answer proved me wrong.我认为只能通过在课堂上声明它来实现, Rawing 的回答证明我错了。

You will need to handle self explicitly.您将需要明确处理self

class TestWrapper():
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.c = 0

    def enter_exit_info(func):
        def wrapper(self, *arg, **kw):
            print '-- entering', func.__name__
            print '-- ', self.__dict__
            res = func(self, *arg, **kw)
            print '-- exiting', func.__name__
            print '-- ', self.__dict__
            return res
        return wrapper

    @enter_exit_info
    def add_in_c(self):
        self.c = self.a + self.b
        print self.c

    @enter_exit_info
    def mult_in_c(self):
        self.c = self.a * self.b
        print self.c


if __name__ == '__main__':
    t = TestWrapper(2, 3)
    t.add_in_c()
    t.mult_in_c()

This is valid python, but it's somewhat weird to have a function at the class level which is not really a method.这是有效的python,但在类级别拥有一个实际上不是方法的函数有点奇怪。 Unless you have a good reason to do it this way, it would be more idiomatic to move the decorator to module level scope.除非你有充分的理由这样做,否则将装饰器移动到模块级范围会更惯用。

Instead of defining the decorator inside the class you can just intercept the self parameter:您可以拦截self参数,而不是在类中定义装饰器:

def enter_exit_info(func):
    def wrapper(self, *arg, **kw):
        print '-- entering', func.__name__
        print '-- ', self.__dict__
        res = func(self, *arg, **kw)
        print '-- exiting', func.__name__
        print '-- ', self.__dict__
        return res
    return wrapper

class TestWrapper():
    def __init__(self, a, b):
        self.a = a
        self.b = b
        self.c = 0

    @enter_exit_info
    def add_in_c(self):
        self.c = self.a + self.b
        print self.c

    @enter_exit_info
    def mult_in_c(self):
        self.c = self.a * self.b
        print self.c


if __name__ == '__main__':
    t = TestWrapper(2, 3)
    t.add_in_c()
    t.mult_in_c()

TL;DR : what you want is TL;DR:你想要的是

def enter_exit_info(func):
    def wrapper(self, *arg, **kw):
        print '-- entering', func.__name__
        print '-- ', self.__dict__
        res = func(*arg, **kw)
        print '-- exiting', func.__name__
        print '-- ', self.__dict__
        return res
    return wrapper

Remember that请记住

@decorate
def myfunc():
    pass

is really just syntactic sugar for真的只是语法糖

def myfunc():
    pass
my_func = decorate(my_func)

So since in your case, decorated functions are replaced by the decorator's wrapper function, it's this wrapper function that will receive the current instance as first argument.因此,由于在您的情况下,装饰函数被装饰器的wrapper函数替换,因此该wrapper函数将接收当前实例作为第一个参数。

EDIT : I positively agree with other answers on the point that it makes no sense defining this decorator within the class.编辑:我非常同意其他答案,即在类中定义这个装饰器是没有意义的。 You don't need it to access the current instance since it's provided as the function's first argument.您不需要它来访问当前实例,因为它是作为函数的第一个参数提供的。 FWIW the def statement doesn't work any differently from being used within a class statement, it always yields a plain old function object. FWIW def语句与在class语句中使用没有任何不同,它总是产生一个普通的旧function对象。 What makes the function a "method" (and 'automagically' pass the current instance as first argument) is the attribute resolution mechanism, cf https://wiki.python.org/moin/FromFunctionToMethod使函数成为“方法”(并“自动”将当前实例作为第一个参数传递)是属性解析机制,参见https://wiki.python.org/moin/FromFunctionToMethod

Hi do you want the output should be in dictionary format?嗨,你希望输出应该是字典格式吗? If you don't want the output in dictionary format u can try this....如果你不想要字典格式的输出,你可以试试这个......

def enter_exit_info(func):
        def wrapper(*arg, **kw):
            print '-- entering', func.__name__        
            res = func(*arg, **kw)
            print '-- exiting', func.__name__
            return res
        return wrapper

then your output will be那么你的输出将是

-- entering add_in_c

5
-- exiting add_in_c

-- entering mult_in_c

6
-- exiting mult_in_c

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM