注意:
另一个问题的接受答案显示了如何使用父装饰。
此问题的接受答案显示将装饰器移动到模块范围。
class A:
def deco( func ):
print repr(func)
def wrapper( self, *args ):
val = func( *args )
self.do_something()
return val
return wrapper
def do_something( self ):
# Do something
print 'A: Doing something generic for decoration'
@deco
def do_some_A_thing ( self ):
# Do something
print 'A: Doing something generic'
class B ( A ):
@deco
def do_some_B_thing( self ):
# Do something
print "B: Doing something specific"
a = A()
b = B()
a.do_some_A_thing()
b.do_some_B_thing()
#Expected Output:
#A: Doing something generic
#A: Doing something generic for decoration
#B: Doing something specific
#A: Doing something generic for decoration
此代码生成NameError:名称'deco'未在B内定义。 装饰器需要在类范围内,因为我需要访问存储状态。
第三编辑:关于斯文的建议,我试过这个:
class A:
def deco( func ):
def wrapper( self, *args ):
val = func( *args )
self.do_something(*args)
return val
return wrapper
def do_something( self ):
# Do something
print 'A: Doing something generic for decoration'
@deco
def do_some_A_thing ( self ):
# Do something
print 'A: Doing something generic'
deco = staticmethod(deco)
class B ( A ):
@A.deco
def do_some_B_thing( self ):
# Do something
print "B: Doing something specific"
a = A()
b = B()
a.do_some_A_thing()
b.do_some_B_thing()
#Expected Output:
#A: Doing something generic
#A: Doing something generic for decoration
#B: Doing something specific
#A: Doing something generic for decoration
我现在有TypeError:do_some_A_thing()只取1个参数(给定0)。有什么指针吗?
答案 0 :(得分:5)
问题在于继承适用于实例属性查找,而不适用于类定义。所以当你尝试用B中的A.deco装饰时,它找不到它。解决方案是将deco
移到模块范围,因为名称self
没有任何魔力,您可以继续使用它。您还需要明确地将self
传递给func
,而不需要在self.do_something()
中传递它。这是更新后的代码:
def deco( func ):
print repr( func )
def wrapper( self, *args ):
val = func( self, *args )
self.do_something()
return val
return wrapper
class A:
def do_something( self ):
# Do something
print 'A: Doing something generic for decoration'
@deco
def do_some_A_thing ( self ):
# Do something
print 'A: Doing something generic'
class B ( A ):
@deco
def do_some_B_thing( self ):
# Do something
print "B: Doing something specific"
a = A()
b = B()
a.do_some_A_thing()
b.do_some_B_thing()
答案 1 :(得分:2)
回答已修改的问题:您的问题已与question it linked to before the edit完全相同。比链接问题的答案中给出的更简单的解决方法是简单地将装饰器移出类名称空间。
此外,self.do_something(self)
应为self.do_something()
而不是self
两次。
在编辑前回答问题:如果您只想用装饰器修饰实例方法,请不要将self
参数折叠为*args
,而是请明确说明:
def _deco(func):
def wrapper(self, *args):
res = func(self, *args)
self.some_other_baseclass_method(*args)
return res
return wrapper
那就是说,我没有看到在类名称空间中使用_deco
并将其转换为staticmethod
的重点。只需将其移动到模块命名空间即可。