我试图弄清楚如何在使用的子类上使用装饰器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()使用装饰器时使用的子类?理想情况下,我想不时地重复使用一个类,并简单地装饰它而不会破坏它.
基本上,您可以在交互式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)
装饰器创建了一种钻石继承的情况。您可以通过不使用 来避免这些问题super()。更改SubClassAgain为以下内容将防止无限递归:
@class_decorator
class SubClassAgain(BaseClass):
def print_class(self):
BaseClass.print_class(self)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5670 次 |
| 最近记录: |