繁体   English   中英

在 Python 中从子类访问父类中的装饰器

[英]Accessing a decorator in a parent class from the child in Python

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

我(错误地)认为 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() 错误,这并不奇怪。

任何想法如何做到这一点,我真的很想将装饰器封装在类中,但我不喜欢这个想法,我需要在基类和子类中调用它。

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'

还有一种特定于python3的方法可以在子类中使用该装饰器而不提及父类,完全按照OP的建议。 它需要使用其__prepare__()方法在父类的元类中实现装饰器(可以在此处找到元类的很好解释

aaronasterling 的答案是有效且首选的解决方法,我仅将其发布为一个有趣的示例,以帮助其他人了解语言的基础知识。 仅当没有其他方法可以实现您的需要时才使用元类!

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
  • 如果不存在,则使用空映射作为初始本地命名空间。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM