我有几个类是从第三方包的基 Widget 类继承的。我有两组独立的行为,我想有选择地将它们应用于其中一些类(一个、另一个或两者)。使用经典/标准继承设置此行为将导致继承菱形:
class NotMyWidget:
pass
class OptionalBehavior1(NotMyWidget):
pass
class OptionalBehavior2(NotMyWidget):
pass
class MySpecialWidget(OptionalBehavior1, OptionalBehavior2)
pass
class MySpecialWidget2(OptionalBehavior2):
pass
也许我很笨,这实际上是首选解决方案,钻石实际上不是问题。
我需要在 Python 2.7.5 中找出一个好的实现(被依赖它的其他包和 RedHat 7 强制并且没有针对 Python 3 修复,我希望我在这里有一个选择)。
对于我自己的熏陶,我也希望看到 Python 3 解决方案。
我尝试过的,使用装饰器的概念:
import functools
class NotMyWidget:
def __init__(self, parent):
pass
def optional_behavior1(cls):
if not issubclass(cls, NotMyWidget):
raise TypeError('Decorated class must inherit from NotMyWidget')
@functools.wraps(cls, updated=())
class Optional1(cls):
def __init__(self, *args, **kwargs):
super(Optional1, self).__init__(*args, **kwargs)
#special init needs of optional_behavior1 here
#define overloaded methods here to modify NotMyWidget base behavior
return Optional1
def optional_behavior2(cls):
if not issubclass(cls, NotMyWidget):
raise TypeError('Decorated class must inherit from NotMyWidget')
@functools.wraps(cls, updated=())
class Optional2(cls):
def __init__(self, parent, second_arg, *args, **kwargs):
super(Optional2, self).__init__(parent, second_arg, *args, **kwargs)
#special init needs of optional_behavior2 here, including logic based off of second_arg
#define overloaded methods here to modify NotMyWidget base behavior and MySpecialWidget* behavior (second_arg)
return Optional2
@optional_behavior2
@optional_behavior1
class MySpecialWidget(NotMyWidget):
def __init__(self, parent, second_arg, third_arg):
#attempt 1
super(MySpecialWidget, self).__init__(parent)
# -> TypeError: __init__() takes exactly 4 arguments (2 given)
#attempt 2
super(MySpecialWidget, self).__init__(parent, second_arg, third_arg)
# -> RuntimeError: maximum recursion depth exceeded while calling a Python object (Optional2 __init__ run once, Optional1 __init__ run recursively until exception thrown, reversing decorators reverses which class is called once or until error)
#attempt 3
#no super/__init__ invocation included
# -> RuntimeError: super-class __init__() of type MySpecialWidget was never called
#attempt 4
#no super/__init__ invocation included here
#call to super(cls, self).__init__(parent) in both __init__ methods of Optional1 and Optional2, before their own super/__init__ invocations
# -> TypeError: __init__() takes exactly 4 arguments (2 given)
#attempt 5
#no super/__init__ invocation included here
#call to super(cls, self).__init__(<same args as Optional1 or Optional2 super/__init__ invocation) in __init__ method of Optional1 and Optional2, before their own super/__init__ invocations
# -> RuntimeError: super-class __init__() of type MySpecialWidget was never called
我有一些尝试 4 或 5 的变体似乎莫名其妙地起作用,但我认为在 MySpecialWidget 的 init 方法中没有 super/init 调用是非常奇怪的,所以我跳回兔子洞从那以后就再也没有看到过正常运行的版本。我很明显误解了 Python 继承和 super/init.
的行为