class A:
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
B() # output: hello
在我使用过的所有其他语言中,超级构造函数被隐式调用。如何在 Python 中调用它?我希望 super(self)
但这不起作用。
super().__init__(args...)
super()
的更改,@Aidan 是迄今为止最合适的
与其他答案一致,有多种方法可以调用超类方法(包括构造函数),但是在 Python-3.x 中,该过程已被简化:
Python-3.x
class A(object):
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
super().__init__()
Python-2.x
在 python 2.x 中,您必须调用稍微详细一点的版本 super(<containing classname>, self)
,它相当于 super()
按照 the docs。
class A(object):
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
super(B, self).__init__()
super()
返回一个类父对象在新式类中:
class A(object):
def __init__(self):
print("world")
class B(A):
def __init__(self):
print("hello")
super(B, self).__init__()
B()
使用 Python 2.x 旧式类,它会是这样的:
class A:
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
A.__init__(self)
super
而不必直接命名要继承的类。
super
的最不重要的原因之一。
一种方法是调用 A 的构造函数并将 self
作为参数传递,如下所示:
class B(A):
def __init__(self):
A.__init__(self)
print "hello"
这种风格的优点是非常清晰。它调用 A 的初始化程序。缺点是它不能很好地处理菱形继承,因为您最终可能会调用共享基类的初始化程序两次。
另一种方法是使用 super(),正如其他人所展示的那样。对于单继承,它与让您调用父级的初始化程序基本相同。
然而,super() 在底层要复杂得多,有时在多重继承情况下可能违反直觉。从好的方面来说,super() 可用于处理菱形继承。如果您想了解 super() 的具体功能,我找到的关于 super() 工作原理的最佳解释是 here(尽管我不一定赞同那篇文章的观点)。
A.__init__(self)
行的情况下正常工作。
A.__init__
的实际作用。它可能会以恒定方式初始化各种内部属性(例如 self.stuff = []
),如果您不调用 A.__init__
,这可能会导致您的 B
实例无法正常运行。
简答
super(DerivedClass, self).__init__()
长答案
super()
做什么?
它采用指定的类名,找到它的基类(Python 允许多重继承)并从左到右在每个基类中查找方法(在本例中为 __init__
)。一旦找到可用的方法,它就会调用它并结束搜索。
如何调用所有基类的 init?
如果您只有一个基类,则上述方法有效。但是 Python 确实允许多重继承,您可能希望确保所有基类都正确初始化。为此,您应该让每个基类调用 init:
class Base1:
def __init__():
super(Base1, self).__init__()
class Base2:
def __init__():
super(Base2, self).__init__()
class Derived(Base1, Base2):
def __init__():
super(Derived, self).__init__()
如果我忘记为 super 调用 init 怎么办?
构造函数 (__new__
) 在链中被调用(如在 C++ 和 Java 中)。创建实例后,仅调用该实例的初始化程序 (__init__
),而没有任何指向其超类的隐式链。
__new__
也没有被链接。如果您的示例中的所有三个类都定义了 __new__
,但没有使用 super().__new__()
,那么 Derived()
将调用 Derived.__new__
而不是 Base1.__new__
或 Base2.__new__
。但是,不调用其父级 __new__
的 __new__
几乎是无用的,因为最终 object.__new__
是唯一真正创建任何新实例的东西。
只是添加一个带参数的示例:
class B(A):
def __init__(self, x, y, z):
A.__init__(self, x, y)
给定一个需要定义变量 x、y、z 的派生类 B,以及一个需要定义 x、y 的超类 A,您可以使用对当前子类实例的引用来调用超类 A 的静态方法 init (self) 然后是预期参数的列表。
我使用以下公式扩展先前的答案:
class A(object):
def __init__(self):
print "world"
class B(A):
def __init__(self):
print "hello"
super(self.__class__, self).__init__()
B()
这样您就不必在调用 super 时重复类的名称。如果您正在编写大量类,并且希望在初始化方法中使您的代码独立于类名,它会派上用场。
C
扩展 B
,您将得到不定式递归,并且 self.__class__
指向 C(B)
而不是 B(A)
,因此 super(self.__class__, self)
指向 B
而不是 A
。
B
进行子类化时,这将导致无限递归错误。 不要使用 self.__class__
或 type(self)
,要么传入显式类(此处为 B
),要么在 Python 3 中使用不带参数的 super()
。
不定期副业成功案例分享
super(B,self)
需要同时提及 B 和 self ?这不是多余的吗? self 不应该包含对 B 的引用吗?self
实际上可能是C
的一个实例,即B
的子级。super()
,您应该能够编写super().__init__()
无参数。