__init__ 是 class 方法吗?
Is __init__ a class method?
我正在研究 Python 的超级方法和多重继承。我读到了一些东西,比如当我们使用 super 调用一个在所有基 classes 中都有实现的基方法时,即使有各种参数,也只会调用一个 class' 方法。例如,
class Base1(object):
def __init__(self, a):
print "In Base 1"
class Base2(object):
def __init__(self):
print "In Base 2"
class Child(Base1, Base2):
def __init__(self):
super(Child, self).__init__('Intended for base 1')
super(Child, self).__init__()# Intended for base 2
这会为第一个 super
方法生成 TyepError
。 super
将调用它首先识别并给出 TypeError
的任何方法实现,而不是检查其他 classes。但是,当我们执行以下操作时,这将更加清晰并且可以正常工作:
class Child(Base1, Base2):
def __init__(self):
Base1.__init__(self, 'Intended for base 1')
Base2.__init__(self) # Intended for base 2
这引出了两个问题:
__init__
方法是静态方法还是class方法?
- 为什么要使用 super,它隐式地自行选择方法而不是像后一个示例那样显式调用方法?对我来说,它看起来比使用 super 干净得多。那么使用
super
比第二种方式有什么优势(除了在方法调用中编写基础 class 名称)
关于你的第一个问题,__init__
既不是静态方法也不是class方法;它是一个普通的实例方法。 (也就是说,它接收实例作为它的第一个参数。)
关于你的第二个问题,如果你想显式调用多个基class实现,那么像你那样显式地调用确实是唯一的方法。但是,您似乎误解了 super
的工作原理。当您调用 super
时,如果您已经调用它,它不会 "know"。您对 super(Child, self).__init__
的两次调用都调用了 Base1 实现,因为那是 "nearest parent"(Child
的最直接的超级 class)。
如果你想调用 just 这个直接的 superclass 实现,你可以使用 super
。如果那个 superclass 也被设置为调用它的 superclass,那么你会这样做。 super
的使用方法是让每个class只调用class层级中的下一个实现"up",这样super
的调用顺序就是整体调用需要按正确顺序调用的所有内容。这种类型的设置通常称为 "cooperative inheritance",您可以在网上找到有关它的各种文章,包括 here and here。
super()
面对多重继承,尤其是 object
can get a bit tricky 上存在的方法。一般规则是,如果您使用 super
,那么 层次结构 中的每个 class 都应该使用 super
。为 __init__
处理这个问题的一个好方法是让每个方法都采用 **kwargs
,并且始终在所有地方使用关键字参数。当调用 object.__init__
时,所有参数都应该已经弹出!
class Base1(object):
def __init__(self, a, **kwargs):
print "In Base 1", a
super(Base1, self).__init__()
class Base2(object):
def __init__(self, **kwargs):
print "In Base 2"
super(Base2, self).__init__()
class Child(Base1, Base2):
def __init__(self, **kwargs):
super(Child, self).__init__(a="Something for Base1")
有关其工作原理以及如何使其为您工作的更多说明,请参阅链接文章!
编辑:冒着回答两个问题的风险,"Why use super at all?"
出于许多与我们拥有 classes 和继承相同的原因,我们拥有 super()
作为模块化和抽象代码的工具。在 class 的实例上操作时,您不需要知道 class 是如何实现的所有细节,您只需要知道它的方法和属性,以及您如何打算将 public 接口用于 class。特别是,您可以确信,class 的实施变化不会给您作为其实例的用户带来问题。
从基础 classes 派生新类型时,同样的论点成立。您不想也不需要担心这些基础 classes 是如何实现的。这是一个具体的例子,说明不使用 super 可能会出错。假设你有:
class Foo(object):
def frob(self):
print "frobbign as a foo"
class Bar(object):
def frob(self):
print "frobbign as a bar"
然后你做了一个子class:
class FooBar(Foo, Bar):
def frob(self):
Foo.frob(self)
Bar.frob(self)
一切都很好,但当你认真对待它时,你会意识到,
Foo
确实是一种Bar
,你改一下
class Foo(Bar):
def frob(self):
print "frobbign as a foo"
Bar.frob(self)
这一切都很好,除了在您的派生 class 中,FooBar.frob()
调用 Bar.frob()
两次 。
这正是 super()
解决的问题,它可以防止您多次调用 superclass 实现(当按指示使用时...)
我正在研究 Python 的超级方法和多重继承。我读到了一些东西,比如当我们使用 super 调用一个在所有基 classes 中都有实现的基方法时,即使有各种参数,也只会调用一个 class' 方法。例如,
class Base1(object):
def __init__(self, a):
print "In Base 1"
class Base2(object):
def __init__(self):
print "In Base 2"
class Child(Base1, Base2):
def __init__(self):
super(Child, self).__init__('Intended for base 1')
super(Child, self).__init__()# Intended for base 2
这会为第一个 super
方法生成 TyepError
。 super
将调用它首先识别并给出 TypeError
的任何方法实现,而不是检查其他 classes。但是,当我们执行以下操作时,这将更加清晰并且可以正常工作:
class Child(Base1, Base2):
def __init__(self):
Base1.__init__(self, 'Intended for base 1')
Base2.__init__(self) # Intended for base 2
这引出了两个问题:
__init__
方法是静态方法还是class方法?- 为什么要使用 super,它隐式地自行选择方法而不是像后一个示例那样显式调用方法?对我来说,它看起来比使用 super 干净得多。那么使用
super
比第二种方式有什么优势(除了在方法调用中编写基础 class 名称)
关于你的第一个问题,__init__
既不是静态方法也不是class方法;它是一个普通的实例方法。 (也就是说,它接收实例作为它的第一个参数。)
关于你的第二个问题,如果你想显式调用多个基class实现,那么像你那样显式地调用确实是唯一的方法。但是,您似乎误解了 super
的工作原理。当您调用 super
时,如果您已经调用它,它不会 "know"。您对 super(Child, self).__init__
的两次调用都调用了 Base1 实现,因为那是 "nearest parent"(Child
的最直接的超级 class)。
如果你想调用 just 这个直接的 superclass 实现,你可以使用 super
。如果那个 superclass 也被设置为调用它的 superclass,那么你会这样做。 super
的使用方法是让每个class只调用class层级中的下一个实现"up",这样super
的调用顺序就是整体调用需要按正确顺序调用的所有内容。这种类型的设置通常称为 "cooperative inheritance",您可以在网上找到有关它的各种文章,包括 here and here。
super()
面对多重继承,尤其是 object
can get a bit tricky 上存在的方法。一般规则是,如果您使用 super
,那么 层次结构 中的每个 class 都应该使用 super
。为 __init__
处理这个问题的一个好方法是让每个方法都采用 **kwargs
,并且始终在所有地方使用关键字参数。当调用 object.__init__
时,所有参数都应该已经弹出!
class Base1(object):
def __init__(self, a, **kwargs):
print "In Base 1", a
super(Base1, self).__init__()
class Base2(object):
def __init__(self, **kwargs):
print "In Base 2"
super(Base2, self).__init__()
class Child(Base1, Base2):
def __init__(self, **kwargs):
super(Child, self).__init__(a="Something for Base1")
有关其工作原理以及如何使其为您工作的更多说明,请参阅链接文章!
编辑:冒着回答两个问题的风险,"Why use super at all?"
出于许多与我们拥有 classes 和继承相同的原因,我们拥有 super()
作为模块化和抽象代码的工具。在 class 的实例上操作时,您不需要知道 class 是如何实现的所有细节,您只需要知道它的方法和属性,以及您如何打算将 public 接口用于 class。特别是,您可以确信,class 的实施变化不会给您作为其实例的用户带来问题。
从基础 classes 派生新类型时,同样的论点成立。您不想也不需要担心这些基础 classes 是如何实现的。这是一个具体的例子,说明不使用 super 可能会出错。假设你有:
class Foo(object):
def frob(self):
print "frobbign as a foo"
class Bar(object):
def frob(self):
print "frobbign as a bar"
然后你做了一个子class:
class FooBar(Foo, Bar):
def frob(self):
Foo.frob(self)
Bar.frob(self)
一切都很好,但当你认真对待它时,你会意识到,
Foo
确实是一种Bar
,你改一下
class Foo(Bar):
def frob(self):
print "frobbign as a foo"
Bar.frob(self)
这一切都很好,除了在您的派生 class 中,FooBar.frob()
调用 Bar.frob()
两次 。
这正是 super()
解决的问题,它可以防止您多次调用 superclass 实现(当按指示使用时...)