【问题标题】:Calling method in superclass not giving the output I expect?在超类中调用方法没有给出我期望的输出?
【发布时间】:2018-08-27 10:28:53
【问题描述】:

我正在学习 Python 中的继承,并且正在试验超类和 super() 函数。这是我的代码:

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

    def describe(self):
        return f"{self.name}, {self.age}, {self.weight}"


class Engineer(Person):
    def __init__(self, name, age, weight):
        super().__init__("Bla bla", 10, 100)
        self.name = name
        self.age = age
        self.weight = weight
        self.occupation = "Engineer"

    def describe(self):
        return super().describe()

my_engineer = Engineer("Larry", 17, 120)
print(my_engineer.describe())

我有 Java 背景,显然super() 在 Python 中的工作方式与在 Java 中的不同。在 Java 中,与此等效的代码的输出将是 Bla bla, 17, 120,但此代码输出的是 Larry, 17, 120。为什么这段代码打印出Larry, 17, 120 而不是我预期的?据我了解,我正在实例化Engineer 类并将"Larry"17120 传递给__init__,但随后我将"Bla bla"10100 传递给超类的__init__,因此应该使用这些值初始化超类。然后当我调用my_engineer.describe() 时,它应该在超类中调用describe() 并使用超类的传入值。但显然,这不是正在发生的事情。谁能解释一下是怎么回事?

【问题讨论】:

  • 你立即替换父__init__设置的属性值,显式;为什么这令人惊讶?
  • “我有 Java 背景,显然 super() 在 Python 中的工作方式与在 Java 中不同。” 你说得对。 super() 在 Python 中的工作方式与在 Java 中不同。作为一个建议,最好不要试图将用一种语言学到的概念投射到你正在学习的另一种语言上。虽然语言确实具有某些广泛的共同点(在这种情况下为继承),但这些概念的实现方式通常非常不同。学习一门新语言时,最好将其视为一种独立的、独特的语言,而不是从所学的其他语言中引入其他思想。

标签: python python-3.x oop superclass


【解决方案1】:

super 工作正常;但是,在super 调用之后,您将使用传递给子构造函数的值覆盖每个属性。相反,只需调用super 并且不要用相同的属性初始化子类:

class Engineer(Person):
   def __init__(self, *args):
      super().__init__("Bla bla", 10, 100)
   def describe(self):
      return super().describe()

my_engineer = Engineer("Larry", 17, 120)
print(my_engineer.describe())

输出:

Bla bla, 10, 100

【讨论】:

    【解决方案2】:

    您会看到属性被覆盖。这些代码行发生了什么:

    super().__init__("Bla bla", 10, 100)
    self.name = name
    self.age = age
    self.weight = weight
    self.occupation = "Engineer"
    
    • super().__init__("Bla bla", 10, 100) 使用这些值调用 Person__init__,即 self = Person("Bla bla", 10, 100)。如果你停在这里,你会实例化Person 的一个子类,并没有真正改变任何东西。 (相同的属性,相同的方法。)
    • 当您随后指定接下来的四个属性时,您将覆盖您在上一行中所做的。这些直接设置为类实例的属性。

    基本上,这看起来像 Python:

    my_engineer = Person("Bla bla", 10, 100)
    my_engineer.name = "Larry"
    my_engineer.age = 17
    my_engineer.weight = 120
    my_engineer.occupation = "Engineer"
    

    正如@Ajax1234 所述,您似乎想完全摆脱这四行。

    【讨论】:

    • 所以我从中得到的是,在 Python 中,最好在子类的 __init__ 末尾调用 super().__init__,而不是在设置属性的开头子类(不像Java,标准是把super()放在开头)?
    • Eh .. 不要粗鲁,但我会说这有点忽略了这一点。虽然很多人出于各种原因不喜欢这本书,但Learn Python the Hard Way 中有一个有用的部分介绍了父/子类交互以及实现它的 3 种方法。
    • 经常看到 super 用来继承一些属性,然后还设置一些父类不附带的附加属性。所以在这种情况下,你会在订单之间无动于衷。
    • 仔细查看您的问题,我想您想最后调用 super() ,但我并没有完全按照您在此处尝试执行的操作。这一切似乎有点多余
    猜你喜欢
    • 1970-01-01
    • 2015-05-30
    • 2017-07-20
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    相关资源
    最近更新 更多