Python 使用_init继承属性__

Python 使用_init继承属性__,python,inheritance,attributes,polymorphism,Python,Inheritance,Attributes,Polymorphism,我是Java人,刚刚开始学习Python。举个例子: class Person(): def __init__(self, name, phone): self.name = name self.phone = phone class Teenager(Person): def __init__(self, name, phone, website): self.name=name self.phone=phone

我是Java人,刚刚开始学习Python。举个例子:

class Person():
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        self.name=name
        self.phone=phone
        self.website=website
我确信有很多冗余代码(我知道在Java中,上面的代码有很多冗余)


对于已经从父类继承的属性,哪些部分是冗余的

在python中为类编写
\uuuuuu init\uuu
函数时,应始终调用其超类的
\uuuu init\uu
函数。我们可以使用它将相关属性直接传递给超类,因此您的代码如下所示:

class Person(object):
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def __init__(self, name, phone, website):
        Person.__init__(self, name, phone)
        self.website=website
正如其他人所指出的,您可以替换该行

Person.__init__(self, name, phone)

代码也会做同样的事情。这是因为在python中,
instance.method(args)
只是
Class.method(instance,args)
的简写。如果要使用
super
,需要确保指定
object
作为
Person
的基类,就像我在代码中所做的那样


提供了有关如何使用
super
关键字的更多信息。在这种情况下,重要的是它告诉python在
self
的超类中查找方法
\uuuuu init\uuuu
,该超类不是
,python中的属性在构造函数中定义时不会被继承,父类构造函数也不会被调用,除非您手动执行所有操作:

class Person():
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def_init_(self, name, phone, website):
        Person.__init__(self, name, phone)  # Call parent class constructor.
        self.website=website

这里有更多信息:

\uuuu init\uuuu
,与java构造函数不同的是,继承层次结构中的每个类都不会自动调用,您需要自己调用

此外,所有对象层次结构都应以
对象
为根(特殊情况除外)

您的代码应为:

class Person(object):
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone
class Teenager(Person):
    def_init_(self, name, phone, website):
        super(Teenager, self).__init__(name, phone)
        self.website=website
super
为其第二个参数(
self
)创建一个委托,该委托将调用函数列表中的下一个函数来调用每个名称(“方法解析顺序”)。这与在Java中调用超类方法不同


您也可以编写
super(type(self),self)。\uuuu init\uuuu(name,phone)
,但是如果您从这个类继承得更远,
type(self)
可能不是
tender
,并且您可以有一个无限递归。这是一个实际的结果,因为您使用的是具有不同MRO的委托对象,而不是直接调用超类构造函数。

我喜欢这样做的方式稍微简洁一些:

class Teenager(Person):
        def __init__(self, *args, **kwargs):
           self.website=kwargs.pop('website')
           super(Teenager, self).__init__(*args, **kwargs)

在这种情况下,这没有多大区别,但是当您有一个带有大量参数的
\uuu init\uuu
时,它会使生活变得更简单。

到目前为止,所有的示例都是针对Python2.x的,但这里有一个针对Python3.x的解决方案,它使用了较短版本的super(),并且不从对象继承

class Person:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        super().__init__(name, phone)
        self.website = website

请注意,如果您使用的是Python2.x,则必须明确地将
对象
列为
Person
的基类,以便使用
super()
。否则,您必须使用
Person.\uuuu init\uuu
表单。@chepner您能提供一个参考吗?我找不到。指示仅在新样式的类上支持super(),在Python 2.x中,这些类是从
对象继承的类。我没有意识到python类不会像Java中那样自动从公共基类继承。我已经修复了我的代码。投票赞成使用*args和**kwargs(…在参数众多的情况下非常有效)。使用
args
kwargs
通常会导致不一致的行为。明确地从
kwargs
中获取关键字意味着
a',b',c')
将无法正常工作。它失败并出现一个键错误,因为在本例中,
网站
参数[2]
class Person:
    def __init__(self, name, phone):
        self.name = name
        self.phone = phone

class Teenager(Person):
    def __init__(self, name, phone, website):
        super().__init__(name, phone)
        self.website = website