Python decorators:如何在子类中使用父类decorators

2024-05-16 03:13:56 发布

您现在位置:Python中文网/ 问答频道 /正文

注意:

另一个问题的公认答案显示了如何使用父装饰器。

这个问题的公认答案显示将decorator移动到模块范围。


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

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

此代码生成名称错误:名称“deco”未在B中定义。 decorator需要在类范围内,因为我需要访问存储状态。

第三次编辑:在斯文的建议下,我尝试了:

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给定)。有什么线索吗?


Tags: selffordefargssomedosomethinggeneric
2条回答

已编辑问题的答案:您的问题已成为question it linked to before the edit的完全副本。与链接问题的答案中给出的解决方案相比,一个更简单的解决方案是将decorator移出类命名空间。

而且,self.do_something(self)应该是self.do_something()而不是——不要通过self两次。

在编辑之前回答问题:如果您只想用decorator修饰实例方法,请不要将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的意义。只需将其移动到模块名称空间。

问题是继承只适用于实例属性查找,而不适用于类定义。所以当你试图用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()

相关问题 更多 >