简体   繁体   English

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

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

how does one go about accessing a decorator from a base class in a child?如何从孩子的基类访问装饰器?

I assumed (wrongly) that the ffg.我(错误地)认为 ffg. would work:会工作:

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'

This class works fine, but then I create a child class inheriting from this:这个类工作正常,但后来我创建了一个继承自这个的子类:

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


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

This won't even import properly, let alone run.这甚至无法正确导入,更不用说运行了。 @_deco is undefined. @_deco 未定义。 Trying baseclass._deco throws an unbound method _deco() error, which isn't really surprising.尝试 baseclass._deco 会抛出一个未绑定的方法 _deco() 错误,这并不奇怪。

Any idea how to do this, I'd really like to encapsulate the decorator in the class, but I'm not married to the idea and I'd need to call it in the base & the child class.任何想法如何做到这一点,我真的很想将装饰器封装在类中,但我不喜欢这个想法,我需要在基类和子类中调用它。

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'

There is also python3-specific way to use that decorator in child class without mentioning parent, exactly as OP suggested.还有一种特定于python3的方法可以在子类中使用该装饰器而不提及父类,完全按照OP的建议。 It requires decorator to be implemented in parent's metaclass (nice explanation of metaclases can be found here ), using its __prepare__() method.它需要使用其__prepare__()方法在父类的元类中实现装饰器(可以在此处找到元类的很好解释

aaronasterling's answer is valid and preferred way how to solve that, I am posting this only as an interesting example to help others understand the basics of language. aaronasterling 的答案是有效且首选的解决方法,我仅将其发布为一个有趣的示例,以帮助其他人了解语言的基础知识。 Use metaclasses only when there is no other way to achive what you need!仅当没有其他方法可以实现您的需要时才使用元类!

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')

The sample code works well in python3:示例代码在 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

Important notes about __prepare__() method:关于 __prepare__() 方法的重要说明:

  • If present, it runs before the object body is executed如果存在,它将在执行对象主体之前运行
  • Its return value is used as local namespace for the class body at the begining of its evaluation (this way, decorator can be availabe from child's body without using parent's namespace)它的返回值在评估开始时用作类主体的本地命名空间(这样,装饰器可以从子主体中获得,而无需使用父命名空间)
  • It should be implemented as classmethod() and should return mapping object (ie dict )它应该被实现为classmethod()并且应该返回映射对象(即dict
  • If not present, empty mapping is used as initial local namespace.如果不存在,则使用空映射作为初始本地命名空间。

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

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