【问题标题】:The inheritance of attributes using __init__使用 __init__ 继承属性
【发布时间】:2012-02-09 20:33:54
【问题描述】:

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

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 inheritance attributes polymorphism


    【解决方案1】:

    到目前为止,所有示例都是针对 Python 2.x 的,但这里有一个针对 Python 3.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
    

    【讨论】:

      【解决方案2】:

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

      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)
      

      super(Teenager, self).__init__(name, phone)
      

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

      python documentation 包含有关如何使用 super 关键字的更多信息。在这种情况下,重要的是它告诉 python 在不是 Teenagerself 的超类中寻找方法 __init__

      【讨论】:

      • 请注意,如果您使用的是 Python 2.x,则必须将 object 显式列为 Person 的基类才能使用 super()。否则,您必须使用Person.__init__ 表单。
      • @chepner 你能提供一个参考吗?我找不到。
      • docs.python.org/library/functions.html#super 表示 super() 仅在新样式类上受支持,在 Python 2.x 中是继承自 object 的类
      • @chepner 谢谢。我没有意识到 python 类不会像在 Java 中那样自动从公共基类继承。我已经修复了我的代码。
      【解决方案3】:

      __init__ 与 java 构造函数不同,不会为继承层次结构中的每个类自动调用 - 您需要自己做。

      此外,您的所有对象层次结构都应植根于object(特殊情况除外)。

      您的代码应为:

      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).__init__(name, phone),但是如果你从这个类进一步继承,type(self)可能不是Teenager,你可能会有一个无限递归。这是您使用具有不同 MRO 的委托对象这一事实的一个实际结果,而不是直接调用超类构造函数。

      【讨论】:

        【解决方案4】:

        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
        

        更多信息在这里:http://docs.python.org/tutorial/classes.html#inheritance

        【讨论】:

          【解决方案5】:

          我喜欢这样做的更简洁的方式:

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

          在这种情况下并没有太大的区别,但是当您有一个带有大量参数的 __init__ 时,它会让生活变得更轻松。

          【讨论】:

          • 赞成使用 *args 和 **kwargs(...在有大量参数的情况下有效)。
          • 使用argskwargs 通常会导致不一致的行为。从kwargs 中显式获取关键字意味着Teenager('a', 'b', 'c')不会正常工作。它以 KeyError 失败,因为在这种情况下 websiteargs[2]
          猜你喜欢
          • 1970-01-01
          • 2014-02-03
          • 2012-01-31
          • 2015-06-25
          • 2011-09-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-05-08
          相关资源
          最近更新 更多