类中的Python装饰器

可以这样写:

class Test(object): def _decorator(self, foo): foo() @self._decorator def bar(self): pass 

这失败了:@self中的self是未知的

我也试过:

 @Test._decorator(self) 

这也失败了:testing未知

如果想温度。 修改装饰器中的一些实例variables,然后运行修饰的方法,然后再更改它们。

谢谢。

你想做什么是不可能的。 举个例子,下面的代码看起来是否有效:

 class Test(object): def _decorator(self, foo): foo() def bar(self): pass bar = self._decorator(bar) 

这当然是无效的,因为self并没有被定义在这一点上。 Test也是如此,因为直到定义了类(在它的过程中),它才会被定义。 我向你展示了这个代码片断,因为这是你的装饰器片段转换成的。

所以,正如你所看到的,像这样在装饰器中访问实例是不可能的,因为装饰器在定义任何函数/方法的时候被应用,而不是在实例化的时候被应用。

如果您需要课堂级别的访问 ,请尝试以下操作:

 class Test(object): @classmethod def _decorator(cls, foo): foo() def bar(self): pass Test.bar = Test._decorator(Test.bar) 

这样的事情会做你需要的吗?

 class Test(object): def _decorator(foo): def magic( self ) : print "start magic" foo( self ) print "end magic" return magic @_decorator def bar( self ) : print "normal call" test = Test() test.bar() 

这样可以避免调用self来访问装饰器,并将其作为常规方法隐藏在类名称空间中。

 >>> import stackoverflow >>> test = stackoverflow.Test() >>> test.bar() start magic normal call end magic >>> 

编辑在评论中回答问题:

如何在另一个类中使用隐藏的装饰器

 class Test(object): def _decorator(foo): def magic( self ) : print "start magic" foo( self ) print "end magic" return magic @_decorator def bar( self ) : print "normal call" _decorator = staticmethod( _decorator ) class TestB( Test ): @Test._decorator def bar( self ): print "override bar in" super( TestB, self ).bar() print "override bar out" print "Normal:" test = Test() test.bar() print print "Inherited:" b = TestB() b.bar() print 

我在一些debugging情况下使用这种types的装饰器,它允许通过装饰来覆盖类的属性,而不必find调用函数。

 class myclass(object): def __init__(self): self.property = "HELLO" @adecorator(property="GOODBYE") def method(self): print self.property 

这是装饰者代码

 class adecorator (object): def __init__ (self, *args, **kwargs): # store arguments passed to the decorator self.args = args self.kwargs = kwargs def __call__(self, func): def newf(*args, **kwargs): #the 'self' for a method function is passed as args[0] slf = args[0] # replace and store the attributes saved = {} for k,v in self.kwargs.items(): if hasattr(slf, k): saved[k] = getattr(slf,k) setattr(slf, k, v) # call the method ret = func(*args, **kwargs) #put things back for k,v in saved.items(): setattr(slf, k, v) return ret newf.__doc__ = func.__doc__ return newf 

注意:因为我已经使用了一个类装饰器,即使你没有传递任何参数给装饰器类的构造函数,你也需要使用@adecorator()来装饰函数。

我在研究一个非常相似的问题时发现了这个问题。 我的解决scheme是将问题分成两部分。 首先,您需要捕获要与类方法关联的数据。 在这种情况下,handler_for会将Unix命令与该命令输出的处理程序相关联。

 class OutputAnalysis(object): "analyze the output of diagnostic commands" def handler_for(name): "decorator to associate a function with a command" def wrapper(func): func.handler_for = name return func return wrapper # associate mount_p with 'mount_-p.txt' @handler_for('mount -p') def mount_p(self, slurped): pass 

现在我们已经将一些数据与每个类方法关联起来了,我们需要收集这些数据并将其存储在类属性中。

 OutputAnalysis.cmd_handler = {} for value in OutputAnalysis.__dict__.itervalues(): try: OutputAnalysis.cmd_handler[value.handler_for] = value except AttributeError: pass 
 class Example(object): def wrapper(func): @functools.wraps(func) def wrap(self, *args, **kwargs): print "inside wrap" return func(self, *args, **kwargs) return wrap @wrapper def method(self): pass wrapper = staticmethod(wrapper) 

修饰器似乎更适合于修改整个对象 (包括函数对象)的function与通常依赖于实例属性的对象方法的function。 例如:

 def mod_bar(cls): # returns modified class def decorate(fcn): # returns decorated function def new_fcn(self): print self.start_str print fcn(self) print self.end_str return new_fcn cls.bar = decorate(cls.bar) return cls @mod_bar class Test(object): def __init__(self): self.start_str = "starting dec" self.end_str = "ending dec" def bar(self): return "bar" 

输出是:

 >>> import Test >>> a = Test() >>> a.bar() starting dec bar ending dec 

这是我知道(并已经使用)从同一个类中定义的装饰器中访问self一种方法:

 class Thing(object): def __init__(self, name): self.name = name def debug_name(function): def debug_wrapper(*args): self = args[0] print 'self.name = ' + self.name print 'running function {}()'.format(function.__name__) function(*args) print 'self.name = ' + self.name return debug_wrapper @debug_name def set_name(self, new_name): self.name = new_name 

输出(在python 2.7.10上testing):

 >>> a = Thing('A') >>> a.name 'A' >>> a.set_name('B') self.name = A running function set_name() self.name = B >>> a.name 'B' 

上面的例子是愚蠢的,但表明它的工作原理。

迈克尔·斯佩尔(Michael Speer)的回答进一步扩展了这一点:

一个实例方法装饰器,它使用参数和返回值接受参数和作用于函数。

 class Test(object): "Prints if x == y. Throws an error otherwise." def __init__(self, x): self.x = x def _outer_decorator(y): def _decorator(foo): def magic(self, *args, **kwargs) : print("start magic") if self.x == y: return foo(self, *args, **kwargs) else: raise ValueError("x ({}) != y ({})".format(self.x, y)) print("end magic") return magic return _decorator @_outer_decorator(y=3) def bar(self, *args, **kwargs) : print("normal call") print("args: {}".format(args)) print("kwargs: {}".format(kwargs)) return 27 

接着

 In [2]: test = Test(3) test.bar( 13, 'Test', q=9, lollipop=[1,2,3] )​ start magic normal call args: (13, 'Test') kwargs: {'q': 9, 'lollipop': [1, 2, 3]} Out[2]: 27 In [3]: test = Test(4) test.bar( 13, 'Test', q=9, lollipop=[1,2,3] )​ start magic --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-3-576146b3d37e> in <module>() 4 'Test', 5 q=9, ----> 6 lollipop=[1,2,3] 7 ) <ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs) 11 return foo(self, *args, **kwargs) 12 else: ---> 13 raise ValueError("x ({}) != y ({})".format(self.x, y)) 14 print("end magic") 15 return magic ValueError: x (4) != y (3)  In [2]: test = Test(3) test.bar( 13, 'Test', q=9, lollipop=[1,2,3] )​ start magic normal call args: (13, 'Test') kwargs: {'q': 9, 'lollipop': [1, 2, 3]} Out[2]: 27 In [3]: test = Test(4) test.bar( 13, 'Test', q=9, lollipop=[1,2,3] )​ start magic --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-3-576146b3d37e> in <module>() 4 'Test', 5 q=9, ----> 6 lollipop=[1,2,3] 7 ) <ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs) 11 return foo(self, *args, **kwargs) 12 else: ---> 13 raise ValueError("x ({}) != y ({})".format(self.x, y)) 14 print("end magic") 15 return magic ValueError: x (4) != y (3)  In [2]: test = Test(3) test.bar( 13, 'Test', q=9, lollipop=[1,2,3] )​ start magic normal call args: (13, 'Test') kwargs: {'q': 9, 'lollipop': [1, 2, 3]} Out[2]: 27 In [3]: test = Test(4) test.bar( 13, 'Test', q=9, lollipop=[1,2,3] )​ start magic --------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-3-576146b3d37e> in <module>() 4 'Test', 5 q=9, ----> 6 lollipop=[1,2,3] 7 ) <ipython-input-1-428f22ac6c9b> in magic(self, *args, **kwargs) 11 return foo(self, *args, **kwargs) 12 else: ---> 13 raise ValueError("x ({}) != y ({})".format(self.x, y)) 14 print("end magic") 15 return magic ValueError: x (4) != y (3) 

你可以装饰装饰者:

 import decorator class Test(object): @decorator.decorator def _decorator(foo, self): foo(self) @_decorator def bar(self): pass