Python使用super vs static调用基类

时间:2016-03-08 21:00:37

标签: python inheritance super diamond-problem

到处都看,每个人都在说超级()是多么伟大。但是,我倾向于不使用super()因为它使一切比我想要的复杂得多。我已经看到了一些使用super()的流行示例,但它们似乎从未向基类构造函数显示传递位置必需的参数。

我知道Python中的菱形问题,而super()阻止调用base_base类两次。 (在本例中为A类)

A类的构造函数被调用两次是不是很糟糕? (即案例2)

以下是我的两个案例的代码。

案例1:使用super()._ init _()

#abstractclass
class A(object):

    #abstractmethod
    def __init__(self, for_a, *args):
        self.val_a = for_a

#abstractclass
class B(A):

    #abstractmethod
    def __init__(self, for_a, for_b, for_c):
        super().__init__(for_a, for_c)
        self.val_b = for_b

#abstractclass
class C(A):

    #abstractmethod
    def __init__(self, for_a, for_c):
        super().__init__(for_a)
        self.val_c = for_c

class D(B, C):

    def __init__(self, for_a, for_b, for_c, for_d):
        super().__init__(for_a, for_b, for_c)
        self.val_d = for_d

class E(B):

    def __init__(self, for_a, for_b, for_e, *args):
        super().__init__(for_a, for_b, *args)
        self.val_e = for_e

newobject1 = D(1, 2, 3, 4)

newobject2 = E(10, 11, 12, 0)

案例2:静态 - 使用base._ init _(自我)

#abstractclass
class A(object):

    #abstractmethod
    def __init__(self, for_a):
        self.val_a = for_a

#abstractclass
class B(A):

    #abstractmethod
    def __init__(self, for_a, for_b):
        A.__init__(self, for_a)
        self.val_b = for_b

#abstractclass
class C(A):

    #abstractmethod
    def __init__(self, for_a, for_c):
        A.__init__(self, for_a)
        self.val_c = for_c

class D(B, C):

    def __init__(self, for_a, for_b, for_c, for_d):
        B.__init__(self, for_a, for_b)
        C.__init__(self, for_a, for_c)
        self.val_d = for_d

class E(B):

    def __init__(self, for_a, for_b, for_e):
        super().__init__(for_a, for_b)
        self.val_e = for_e

newobject1 = D(1, 2, 3, 4)

newobject2 = E(10, 11, 12)

2 个答案:

答案 0 :(得分:3)

想法是super()支持method resolution order,以便您可以使用cooperative inheritance编写程序。

如果你想调用你的超类'方法,合作继承是有意义的,但你不知道具体是什么超类 - 你只假设该方法与你正在编写的方法具有相同的签名。

在您的示例中,每个__init__都不同,因此这不是合作继承的良好用例。每个班级实际上都需要知道super将要定位的内容才能正确调用它。因此,您在这里super并未获得太多好处。

我们不要忘记:多重继承是混乱的秘诀。您可以遵守一些约定(一组限制),以使您的代码可以理解并保持意大利面条的控制。一个想法是使用一些基类作为mixins。另一个想法是合作继承。 Python有像super这样的语言结构来支持这些,但是如果你可以自由地超越这些界限。这带来了一系列问题。

答案 1 :(得分:0)

  

A类的构造函数被调用两次这么糟糕吗?

当然,如果构造函数很慢,或者它是非幂等的,或者它获取了文件句柄或数据库连接等资源。在更复杂的继承结构中,您可能还会获得4次,或6次的构造函数,或者从子项到祖先的继承图上的路径。

  

我倾向于不使用super()因为它使一切比我想要的复杂得多

这不是super使事情复杂化 - 它是多重继承。避免多重继承中的super只会给你带来与super问题不同,可能更糟的问题。

  

我已经看到了一些使用super()的流行示例,但它们似乎从未在基类构造函数中显示传递位置必需的参数。

这是因为位置构造函数参数不适用于多重继承。如果你想使用像这样的多继承结构,请尝试使用参数keyword-only并使用**kwargs传递无法识别的参数以供其他类处理。 "Python's super() considered super"对如何使其发挥作用有一些很好的建议。