代码之家  ›  专栏  ›  技术社区  ›  Adriano_Pinaffo

Python:如何使用super()初始化2个超类?

  •  0
  • Adriano_Pinaffo  · 技术社区  · 8 年前

    我有两个超类,父亲和母亲,他们将由孩子继承。

    class Father:
      def __init__(self, **kwargs):
        self.fathername = kwargs["ffn"] + " " + kwargs["fln"]
        self.fatherage = kwargs["fa"]
    
    class Mother:
      def __init__(self, **kwargs):
        self.mothername = kwargs["mfn"] + " " + kwargs["mln"]
        self.motherage = kwargs["ma"]
    

    class Child(Father, Mother):
      def __init__(self, **kwargs):
        self.name = kwargs["name"] + " " + kwargs["lastname"]
        self.age = kwargs["age"]
    

    如果我打电话给他们的父母 __init__()

        Father.__init__(self, **kwargs)
        Mother.__init__(self, **kwargs)
    

    但是如何使用super()实现同样的效果呢?如果我像下面这样称呼它,它只初始化父亲而不是母亲(因为父亲是MRO中的下一个)

        super().__init__(**kwargs)
    

    下面就是 __str__() 重写以显示分配的内容。

    def __str__(self):
        return \
        "Im {}, {} years old".format(self.name, self.age) + "\n" + \
        "My dad is {} and he is {} years old".format(self.fathername, self.fatherage) + "\n" + \
        "My mom is {} and she is {} years old".format(self.mothername, self.motherage)
    
    familyname = "Simpson"
    child = Child(**{"name": "Bart", "lastname": familyname, "age": 15, "ffn": "Hommer", "fln": familyname, "fa": 54, "mfn": "Marggie", "mln": familyname, "ma": 46})
    

    当我尝试打印对象时,它将失败,因为母超类从未初始化(当我使用 super() __初始化() )

    print(child)
    
    The program raises a runtime error
    
    Traceback (most recent call last):
      File "/tmp/pyadv.py", line 225, in <module>
        print(child)
      File "/tmp/pyadv.py", line 217, in __str__
        return     "Im {}, {} years old".format(self.name, self.age) + "\n" +     "My dad is {} and he is {} years old".format(self.fathername, self.fatherage) + "\n" +     "My mom is {} and she is {} years old".format(self.mothername, self.motherage)
    AttributeError: 'Child' object has no attribute 'mothername'
    

    那么,如何使用super初始化两个超类呢?

    编辑: 我试图补充 super(Father, self).__init__(**kwargs) 和 super(Mother, self).__init__(**kwargs) 去超级班级 方法,但我得到以下错误:

    Traceback (most recent call last):
      File "/tmp/pyadv.py", line 225, in <module>
        child = Child(**{"name": "Bart", "lastname": familyname, "age": 15, "ffn": "Hommer", "fln": familyname, "fa": 54, "mfn": "Marggie", "mln": familyname, "ma": 46})
      File "/tmp/pyadv.py", line 217, in __init__
        super().__init__(**kwargs)
      File "/tmp/pyadv.py", line 199, in __init__
        super(Father, self).__init__(**kwargs)
      File "/tmp/pyadv.py", line 208, in __init__
        super(Mother, self).__init__(**kwargs)
    TypeError: object.__init__() takes no parameters
    

    我还试图补充 super(Father, self).__init__() 和 super(Mother, self).__init__() (内部没有参数) )去超级班级 __初始化()

    Traceback (most recent call last):
      File "/tmp/pyadv.py", line 225, in <module>
        child = Child(**{"name": "Bart", "lastname": familyname, "age": 15, "ffn": "Hommer", "fln": familyname, "fa": 54, "mfn": "Marggie", "mln": familyname, "ma": 46})
      File "/tmp/pyadv.py", line 217, in __init__
        super().__init__(**kwargs)
      File "/tmp/pyadv.py", line 199, in __init__
        super(Father, self).__init__()
      File "/tmp/pyadv.py", line 206, in __init__
        self.mothername = kwargs["mfn"] + " " + kwargs["mln"]
    KeyError: 'mfn'
    

    解决方案1:

    解决方案2: here .

    class Root:
      def __init__(self, **kwargs):
        pass
    
    class Father(Root):
      def __init__(self, **kwargs):
        self.fathername = kwargs["ffn"] + " " + kwargs["fln"]
        self.fatherage = kwargs["fa"]
        super().__init__(**kwargs)
    
    class Mother(Root):
      def __init__(self, **kwargs):
        self.mothername = kwargs["mfn"] + " " + kwargs["mln"]
        self.motherage = kwargs["ma"]
        super().__init__(**kwargs)
    
    class Child(Father, Mother):
      def __init__(self, **kwargs):
        self.name = kwargs["name"] + " " + kwargs["lastname"]
        self.age = kwargs["age"]
        super().__init__(**kwargs)
      def __str__(self):
        return \
        "Im {}, {} years old".format(self.name, self.age) + "\n" + \
        "My dad is {} and he is {} years old".format(self.fathername, self.fatherage) + "\n" + \
        "My mom is {} and she is {} years old".format(self.mothername, self.motherage)
    
    familyname = "Simpson"
    child = Child(**{"name": "Bart", "lastname": familyname, "age": 15, "ffn": "Homer", "fln": familyname, "fa": 54, "mfn": "Marge", "mln": familyname, "ma": 46})
    
    print(child)
    
    2 回复  |  直到 8 年前
        1
  •  1
  •   Blckknght    8 年前

    Python中的多重继承需要协作。也就是说,两个父类需要知道彼此存在的可能性(尽管它们不需要知道彼此的任何细节)。那么,任何一个先被命名的父母都可以调用另一个父母的名字 __init__ 方法。就是这样 super

    kwargs 听写在你的字典里 电话。当第二个家长试图调用MRO中的最后一个类时,这就成了一个问题, object ,它不希望接收任何关键字参数。相反,每个班级 super().__init__ (除非它知道它的一个父类也需要参数)。

    试试这个:

    class Father:
      def __init__(self, ffn, fln, fa, **kwargs): # name the parameters we expect
        super().__init__(**kwargs)           # pass on any unknown arguments
        self.fathername = ffn + " " + fln    # use parameters by name, rather than via kwargs
        self.fatherage = fa
    
    class Mother:
      def __init__(self, mfn, mln, ma, **kwargs):
        super().__init__(**kwargs)
        self.mothername = mfn + " " + mln
        self.motherage = ma
    
    class Child(Father, Mother):
      def __init__(self, name, lastname, age, **kwargs):
        super().__init__(**kwargs)
        self.name = name " " + lastname
        self.age = age
    
        def __str__(self):
            return \
            "Im {}, {} years old".format(self.name, self.age) + "\n" + \
            "My dad is {} and he is {} years old".format(self.fathername, self.fatherage) + "\n" + \
            "My mom is {} and she is {} years old".format(self.mothername, self.motherage)
    
    
    familyname = "Simpson"
    child = Child(name="Bart", lastname=familyname, age=15, # you can use keyword syntax here
                  ffn="Homer", fln=familyname, fa=54,
                  mfn="Marge", mln=familyname, ma=46)
    print(child)
    

    请注意,在Python3中,通常不需要将任何参数传递给 super()

    最后一个音符。虽然我确信你的代码只是一个例子,但在面向对象设计方面,类的名称是非常糟糕的。继承意味着 IS-A公司 Mother 或者 Father ,但代码说他是,因为他是 和 班级。描述与父母之间人际关系的更好方法是 . 每个孩子 有一个 有-A 使用封装的关系。这意味着,子对象对属性中每个父对象都有一个引用。有趣的是,只需一节课就可以做到这一点(这可能就是为什么你没有学习这一点,如果你被教导继承的话):

    class Person:
        def __init__(self, firstname, lastname, age, father=None, mother=None):
            self.name = firstname + " " + lastname
            self.age = age
            self.father = father  #  set the attributes for our parents here
            self.mother = mother
    
    fn = "Simpson"
    bart = Person("Bart", fn, 15, Person("Homer", fn, 54), Person("Marge", fn, 46))
    
        2
  •  0
  •   user10287394 user10287394    8 年前

    从这本书的公认答案来看 link :

    通过super调用不会调用所有的父级,而是调用下一个 在MRO链中的作用。要使其正常工作,您需要使用 在所有的比赛中都很出色 __init__s

    class Parent1(object):
        def __init__(self):
            super(Parent1, self).__init__()
            self.var1 = 1
    
    class Parent2(object):
        def __init__(self):
            super(Parent2, self).__init__()
            self.var2 = 2
    
    class Child(Parent1, Parent2):
        def __init__(self):
            super(Child, self).__init__()