2011-09-19 55 views
4

注意使用父类的装饰:Python的装饰:如何在子类

对其他问题接受的答案显示了如何使用父decorater。

该问题的接受答案显示将装饰器移动到模块范围。


编辑:使用前面的例子是一个坏主意。希望这是更清晰:

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:名字“装饰”不是内部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 

我现在有类型错误:do_some_A_thing()恰恰(给出0)1个说法。任何指针?

+0

你试过吗?你有错误吗? – bitcycle

回答

5

问题是继承对实例属性查找起作用,而不是类定义。所以当你尝试用B中的A.deco装饰时,它找不到它。解决方法是将deco移出模块范围,并且由于名称self没有什么魔力,您可以继续使用它。你还需要明确地传递给selffunc,和你做需要通过它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() 
+0

该解决方案才会出现,如果子类被同一模块作为子类中定义的工作。如果我在其他地方进口的父类和尝试定义的子类,使用上的子类的方法中的一种装饰,它不再定义。 – user5359531

+0

@ user5359531:什么是不再定义? –

+0

我的意思是,如果你从另一个模块导入 – user5359531

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。只需将其移动到模块名称空间即可。

+0

谢谢Sven。我的问题措辞很差。我已更新它以更好地反映问题。 – GeneralBecos

+0

@GeneralBecos:更新了我的答案。 –

+0

我尝试这种方法,它导致类型错误:do_some_A_thing()采用完全1参数(0给出)。 – GeneralBecos