在类中声明装饰器

问题描述 投票:0回答:4

我正在尝试在Python中使用自定义包装器/装饰器,并且我想在类中声明一个,以便我可以打印属性的快照。我已经尝试过这个问题中的事情,但没有成功。

这就是我想做的(注意:这段代码不起作用,我在下面解释会发生什么)

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()

预期输出是:

-- 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}

但是我这段代码给出了

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)

如果我尝试 
@enter_exit_info(self)

@self.enter_exit_info
,我会得到
NameError
。我能做什么?


编辑:

我首先不需要在类内部声明装饰器

物理

,只要它能够从此类的实例访问属性即可。我以为只能在类中声明才能实现,Rawing的回答证明我错了。

python python-2.7 wrapper decorator python-decorators
4个回答
27
投票
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()

这是有效的Python,但是在类级别有一个函数而不是真正的方法有点奇怪。除非您有充分的理由这样做,否则将装饰器移动到模块级别范围会更惯用。


22
投票
self

参数即可:

import functools

def enter_exit_info(func):
    @functools.wraps(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()



3
投票

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

记住这一点

@decorate def myfunc(): pass

实际上只是
的语法糖

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

因此,在您的情况下,装饰函数被装饰器的 
wrapper

函数替换,因此这个

wrapper
函数将接收当前实例作为第一个参数。

编辑:我完全同意其他答案,因为在类中定义这个装饰器是没有意义的。您不需要它来访问当前实例,因为它是作为函数的第一个参数提供的。 FWIW

def

语句的工作方式与在

class
语句中使用没有任何不同,它总是产生一个普通的旧
function
对象。使函数成为“方法”(并且“自动”将当前实例作为第一个参数传递)的是属性解析机制,参见
https://wiki.python.org/moin/FromFunctionToMethod


-2
投票

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

那么你的输出将是

-- entering add_in_c 5 -- exiting add_in_c -- entering mult_in_c 6 -- exiting mult_in_c

© www.soinside.com 2019 - 2024. All rights reserved.