类装饰器,继承,超级()和最大递归

jam*_*oks 7 python decorator

我试图弄清楚如何在使用的子类上使用装饰器super().由于我的类装饰器创建了另一个子类,因此装饰类似乎可以防止在super()更改className传递给它时使用super(className, self).以下是一个例子:

def class_decorator(cls):
    class _DecoratedClass(cls):
        def __init__(self):
            return super(_DecoratedClass, self).__init__()
    return _DecoratedClass

class BaseClass(object):
    def __init__(self):
        print "class: %s" % self.__class__.__name__
    def print_class(self):
        print "class: %s" % self.__class__.__name__

bc = BaseClass().print_class()

class SubClass(BaseClass):
    def print_class(self):
        super(SubClass, self).print_class()

sc = SubClass().print_class()

@class_decorator
class SubClassAgain(BaseClass):
    def print_class(self):
        super(SubClassAgain, self).print_class()

sca = SubClassAgain()
# sca.print_class() # Uncomment for maximum recursion
Run Code Online (Sandbox Code Playgroud)

输出应该是:

class: BaseClass
class: BaseClass
class: SubClass
class: SubClass
class: _DecoratedClass
Traceback (most recent call last):
File "class_decorator_super.py", line 34, in <module>
sca.print_class()
File "class_decorator_super.py", line 31, in print_class
super(SubClassAgain, self).print_class()
...
...
RuntimeError: maximum recursion depth exceeded while calling a Python object
Run Code Online (Sandbox Code Playgroud)

有没有人知道如何不破坏super()使用装饰器时使用的子类?理想情况下,我想不时地重复使用一个类,并简单地装饰它而不会破坏它.

Ale*_*lli 5

基本上,您可以在交互式Python提示符下输入代码示例后看到问题:

>>> SubClassAgain
<class '__main__._DecoratedClass'>
Run Code Online (Sandbox Code Playgroud)

即,该名称SubClassAgain现在被绑定(在全局范围内,在这种情况下)到一个实际上不是 "真实" SubClassAgain但是其子类的类.因此,对该名称的任何后期绑定引用,就像它在super(SubClassAgain,调用中所拥有的那样,当然会得到由该名称伪装的子类 - 该子类的超类当然是"真实的SubClassAgain",从而无限递归.

你可以非常简单地重现同样的问题而不用装饰,只需让任何子类篡改它的基类名称:

>>> class Base(object):
...   def pcl(self): print 'cl: %s' % self.__class__.__name__
... 
>>> class Sub(Base):
...   def pcl(self): super(Sub, self).pcl()
... 
>>> Sub().pcl()
cl: Sub
>>> class Sub(Sub): pass
... 
Run Code Online (Sandbox Code Playgroud)

现在,Sub().pcl()由于"名称篡改" ,将导致无限递归.类装饰,除非你用它来装饰和返回你作为参数获得的同一个类,它是系统的"名称篡改",因此与类名的使用不相容,类名绝对必须返回该名称的"true"类,并且不是篡位者(无论是否在其中self).

变通方法 - 如果你绝对必须同时将类装饰作为篡夺(不仅仅是通过接收类参数的变化进行类装饰),并且 super - 基本上需要篡夺者与可能的篡改之间的合作协议,例如以下小的变化到您的示例代码:

def class_decorator(cls):
    class _DecoratedClass(cls):
    _thesuper = cls
        def __init__(self):
            return super(_DecoratedClass, self).__init__()
    return _DecoratedClass

   ...

@class_decorator
class SubClassAgain(BaseClass):
    def print_class(self):
    cls = SubClassAgain
    if '_thesuper' in cls.__dict__:
        cls = cls._thesuper
        super(cls, self).print_class()
Run Code Online (Sandbox Code Playgroud)


Jes*_*e L 3

装饰器创建了一种钻石继承的情况。您可以通过不使用 来避免这些问题super()。更改SubClassAgain为以下内容将防止无限递归:

@class_decorator
class SubClassAgain(BaseClass):
    def print_class(self):
        BaseClass.print_class(self)
Run Code Online (Sandbox Code Playgroud)