类中的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