Python 使用 super vs static 调用 base class
Python calling base class using super vs static
无论我走到哪里,每个人都在说 super() 有多棒。但是,我倾向于不使用 super() 因为它使一切都比我想要的复杂得多。我见过一些使用 super() 的流行示例,但它们似乎从未显示将位置所需的参数传递给基础 class 构造函数。
我知道 Python 中的菱形问题,并且 super() 阻止调用 base_base class 两次。 (在本例中 Class A)
Class 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 _(self)
#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)
Is it so bad that Class A's constructor is called twice?
当然,如果构造函数速度慢,或者它是非幂等的,或者它获取文件句柄或数据库连接等资源。在更复杂的继承结构中,您还可能会调用构造函数 4 次或 6 次,或者与继承图中从子级到祖先的路径一样多的次数。
I'm leaning toward not using super() because it makes everything much more complicated than I would like
这不是 super
让事情变得复杂 - 这是多重继承。在多重继承中避免 super
只会给你带来不同的、可能比 super
的问题更糟糕的问题。
I've seen some popular examples of using super() but they never seem to show passing positional required arguments into the base class constructors.
这是因为位置构造函数参数不适用于多重继承。如果你想使用像这样的多重继承结构,尝试将参数设置为仅关键字并使用 **kwargs
传递无法识别的参数以供其他 类 处理。 "Python's super() considered super" 有一些关于如何让它发挥作用的好建议。
想法是 super()
是为了支持 method resolution order so that you could write your programs using cooperative inheritance。
如果您想调用您的 superclass' 方法,合作继承是有意义的,但您不知道具体的 superclass 是什么 - 您只假设该方法与您正在编写的方法具有相同的签名。
在您的示例中,每个 __init__
都是不同的,因此这不是合作继承的好用例。每个 class 实际上需要知道 super
的目标是什么才能正确调用它。因此,您实际上并没有从此处的 super
中获得太多好处。
我们不要忘记:多重继承是一团糟的秘诀。您可以遵守一些约定(限制集),以使您的代码易于理解并控制意大利面条。一个想法是使用一些基础 classes 作为混入。另一个想法是合作继承。 Python 有像 super
这样的语言结构来支持这些,但如果你可以自由地超越这些界限。这有其自身的一系列问题。
无论我走到哪里,每个人都在说 super() 有多棒。但是,我倾向于不使用 super() 因为它使一切都比我想要的复杂得多。我见过一些使用 super() 的流行示例,但它们似乎从未显示将位置所需的参数传递给基础 class 构造函数。
我知道 Python 中的菱形问题,并且 super() 阻止调用 base_base class 两次。 (在本例中 Class A)
Class 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 _(self)
#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)
Is it so bad that Class A's constructor is called twice?
当然,如果构造函数速度慢,或者它是非幂等的,或者它获取文件句柄或数据库连接等资源。在更复杂的继承结构中,您还可能会调用构造函数 4 次或 6 次,或者与继承图中从子级到祖先的路径一样多的次数。
I'm leaning toward not using super() because it makes everything much more complicated than I would like
这不是 super
让事情变得复杂 - 这是多重继承。在多重继承中避免 super
只会给你带来不同的、可能比 super
的问题更糟糕的问题。
I've seen some popular examples of using super() but they never seem to show passing positional required arguments into the base class constructors.
这是因为位置构造函数参数不适用于多重继承。如果你想使用像这样的多重继承结构,尝试将参数设置为仅关键字并使用 **kwargs
传递无法识别的参数以供其他 类 处理。 "Python's super() considered super" 有一些关于如何让它发挥作用的好建议。
想法是 super()
是为了支持 method resolution order so that you could write your programs using cooperative inheritance。
如果您想调用您的 superclass' 方法,合作继承是有意义的,但您不知道具体的 superclass 是什么 - 您只假设该方法与您正在编写的方法具有相同的签名。
在您的示例中,每个 __init__
都是不同的,因此这不是合作继承的好用例。每个 class 实际上需要知道 super
的目标是什么才能正确调用它。因此,您实际上并没有从此处的 super
中获得太多好处。
我们不要忘记:多重继承是一团糟的秘诀。您可以遵守一些约定(限制集),以使您的代码易于理解并控制意大利面条。一个想法是使用一些基础 classes 作为混入。另一个想法是合作继承。 Python 有像 super
这样的语言结构来支持这些,但如果你可以自由地超越这些界限。这有其自身的一系列问题。