正确使用类装饰器的Python继承super和__init__,装饰类

问题描述 投票:0回答:0

我有几个类是从第三方包的基 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.

的行为
python-2.7 inheritance decorator multiple-inheritance init
© www.soinside.com 2019 - 2024. All rights reserved.