【问题标题】:Accessing a decorator in a parent class from the child in Python在 Python 中从子类访问父类中的装饰器
【发布时间】:2011-03-26 04:20:27
【问题描述】:

如何从孩子的基类访问装饰器?

我(错误地)认为 ffg.会工作:

class baseclass(object):
    def __init__(self):
        print 'hey this is the base'

    def _deco(func):
        def wrapper(*arg):
            res = func(*arg)
            print 'I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling'
            return res
        return wrapper

    @_deco
    def basefunc(self):
        print 'I\'m a base function'

这个类工作正常,但是我创建了一个继承自这个的子类:

class otherclass(baseclass):
    def __init__(self):
        super(otherclass, self).__init__()
        print 'other class'


    @_deco
    def meh(self):
        print 'I\'m a function'

这甚至无法正确导入,更不用说运行了。 @_deco 未定义。尝试 baseclass._deco 会引发未绑定方法 _deco() 错误,这并不奇怪。

知道如何做到这一点,我真的很想将装饰器封装在类中,但我并没有接受这个想法,我需要在基类和子类中调用它。

【问题讨论】:

  • 这个用例是一个用于 pylons 控制器的粗略时序装饰器。所以它需要可以从基类访问,因为那里有需要定时的函数,而子类中的函数需要定时。我想最简单的方法就是把它从课堂上撕下来。
  • 您能更正您的格式吗?您的类的 def __init__ 与类定义的缩进相同。

标签: python decorator


【解决方案1】:

还有一种特定于 python3 的方法可以在子类中使用该装饰器而不提及父类,正如 OP 所建议的那样。它需要使用它的__prepare__() 方法在父元类中实现装饰器(可以在here 找到元类的详细解释)。

aaronasterling's answer 是有效且首选的解决方法,我仅将其作为一个有趣的示例发布,以帮助其他人理解语言的基础知识。只有在没有其他方法可以满足您的需求时才使用元类!

class metaclass(type):
    @classmethod
    def __prepare__(metacls, name, bases):
        def _deco(func):
            def wrapper(*arg):
                res = func(*arg)
                print('I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling')
                return res
            return wrapper
        return {"_deco": _deco}

class baseclass(metaclass=metaclass):
    def __init__(self):
        print('hey this is the base')

    @_deco
    def basefunc(self):
        print('I\'m a base function')
        
class otherclass(baseclass):
    def __init__(self):
        super(otherclass, self).__init__()
        print('other class')

    @_deco
    def meh(self):
        print('I\'m a function')

示例代码在python3中运行良好:

>>> obj = otherclass()
hey this is the base
other class
>>> obj.meh()
I'm a function
I'm a decorator. This is fabulous, but that colour, so last season sweetiedarling

关于 __prepare__() 方法的重要说明:

  • 如果存在,它会在对象主体执行之前运行
  • 它的返回值在其评估开始时用作类主体的本地命名空间(这样,装饰器可以从子主体中获得,而无需使用父命名空间)
  • 它应该被实现为classmethod()并且应该返回映射对象(即dict
  • 如果不存在,则使用空映射作为初始本地命名空间。

【讨论】:

    【解决方案2】:
    class baseclass(object):
        def __init__(self):
            print 'hey this is the base'
    
        def _deco(func):
            def wrapper(*arg):
                res = func(*arg)
                print 'I\'m a decorator. This is fabulous, but that colour, so last season sweetiedarling'
                return res
            return wrapper
    
        @_deco
        def basefunc(self):
            print 'I\'m a base function'
    
        @_deco
        def basefunc2(self):
            print "I'm another base function"
    
       #no more uses of _deco in this class
        _deco = staticmethod(_deco) 
       # this is the key. it must be executed after all of the uses of _deco in 
       # the base class. this way _deco is some sort weird internal function that 
       # can be called from within the class namespace while said namespace is being 
       # created and a proper static method for subclasses or external callers.
    
    
    class otherclass(baseclass):
        def __init__(self):
            super(otherclass, self).__init__()
            print 'other class'
    
    
        @baseclass._deco
        def meh(self):
            print 'I\'m a function'
    

    【讨论】:

    • 太棒了,我要一些,这个季节就是这样,亲爱的。 (我以为我会选择主题。)
    • 我还发现你也可以使用@staticmethod 装饰器,但前提是你没有在基类中声明@_deco(你是)。所以这个解决方案似乎更适合被问到的问题。
    • 小心使用双下划线(如__deco),这会导致一些命名技巧。
    猜你喜欢
    • 2019-08-07
    • 2011-11-20
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 2012-04-21
    • 2016-03-17
    • 1970-01-01
    相关资源
    最近更新 更多