可以这样写吗:
class Test(object):
def _decorator(self, foo):
foo()
@self._decorator
def bar(self):
pass
这个失败了:@self中的self是未知的
我还试过:
@Test._decorator(self)
同样失败:测试未知
我想暂时改变一些实例变量 在装饰器中再运行被装饰的方法 把它们换回来。
可以这样写吗:
class Test(object):
def _decorator(self, foo):
foo()
@self._decorator
def bar(self):
pass
这个失败了:@self中的self是未知的
我还试过:
@Test._decorator(self)
同样失败:测试未知
我想暂时改变一些实例变量 在装饰器中再运行被装饰的方法 把它们换回来。
当前回答
装饰器似乎更适合修改整个对象(包括函数对象)的功能,而不是对象方法的功能,后者通常依赖于实例属性。例如:
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
其他回答
在内部类中声明。 这个解决方案非常可靠,值得推荐。
class Test(object):
class Decorators(object):
@staticmethod
def decorator(foo):
def magic(self, *args, **kwargs) :
print("start magic")
foo(self, *args, **kwargs)
print("end magic")
return magic
@Decorators.decorator
def bar( self ) :
print("normal call")
test = Test()
test.bar()
结果:
>>> test = Test()
>>> test.bar()
start magic
normal call
end magic
>>>
你可以装饰装饰器:
import decorator
class Test(object):
@decorator.decorator
def _decorator(foo, self):
foo(self)
@_decorator
def bar(self):
pass
这样的东西能满足你的需要吗?
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
输出:
Normal:
start magic
normal call
end magic
Inherited:
start magic
override bar in
start magic
normal call
end magic
override bar out
end magic
import functools
class Example:
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):
print("METHOD")
wrapper = staticmethod(wrapper)
e = Example()
e.method()
以下是对迈克尔•施佩尔的回答的进一步扩展:
一个实例方法装饰器,它接受参数并作用于带有参数和返回值的函数。
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)