繁体   English   中英

如何创建多个继承class的实例?

[英]How to create instance of multiple inherited class?

我有这段代码:

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

class Student(Person):
    def __init__(self, name, last_name, age, indexNr, notes):
        super().__init__(name, last_name, age)
        self.indexNr = indexNr
        self.notes = notes

class Employee(Person):
    def __init__(self, name, last_name, age, salary, position):
        super().__init__(name, last_name, age)
        self.salary = salary
        self.position = position

class WorkingStudent(Student, Employee):
    def __init__(self, name, last_name, age, indexNr, notes, salary, position):
        Student.__init__(name, last_name, age, indexNr, notes)
        Employee.__init__(name, last_name, age, salary, position)

我想像这样创建一个 WorkingStudent 实例:

ws = WorkingStudent("john", "brown", 18, 1, [1,2,3], 1000, 'Programmer')

但它不起作用,我收到此错误:

TypeError: __init__() missing 1 required positional argument: 'notes'

或者我在这里做错了什么? 另外,我已经在 WorkingStudent class 中尝试过super()但它只调用第一个传递的 class 的构造函数。即在这种情况下Student

注意:我已经经历了多个 StackOverflow 查询,但我找不到任何可以回答这个问题的东西。 (或者也许我错过了)。

代替显式类,使用super()沿 mro 传递参数:

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

class Student(Person):
    def __init__(self, name, last_name, age, indexNr, notes, salary, position):
        # since Employee comes after Student in the mro, pass its arguments using super
        super().__init__(name, last_name, age, salary, position)
        self.indexNr = indexNr
        self.notes = notes

class Employee(Person):
    def __init__(self, name, last_name, age, salary, position):
        super().__init__(name, last_name, age)
        self.salary = salary
        self.position = position

class WorkingStudent(Student, Employee):
    def __init__(self, name, last_name, age, indexNr, notes, salary, position):
        # pass all arguments along the mro
        super().__init__(name, last_name, age, indexNr, notes, salary, position)

# uses positional arguments            
ws = WorkingStudent("john", "brown", 18, 1, [1,2,3], 1000, 'Programmer')
# then you can print stuff like
print(f"My name is {ws.name} {ws.last_name}. I'm a {ws.position} and I'm {ws.age} years old.")
# My name is john brown. I'm a Programmer and I'm 18 years old.

检查先生:

WorkingStudent.__mro__
(__main__.WorkingStudent,
 __main__.Student,
 __main__.Employee,
 __main__.Person,
 object)

当你创建一个 WorkingStudent 的实例时,最好传递关键字参数,这样你就不必担心弄乱参数的顺序。

由于 WorkingStudent 将属性的定义推迟到父类,因此立即使用super().__init__(**kwargs)将所有参数向上传递,因为子类不需要知道它不处理的参数。 第一个父类是 Student,所以 self.IndexNr 等在那里定义。 mro 中的下一个父类是 Employee,因此从 Student 中,将剩余的关键字参数传递给它,再次使用super().__init__(**kwargs) 从 Employee 开始,定义在那里定义的属性,然后再次通过super().__init__(**kwargs)将其余的属性传递给 mro(到 Person)。

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

class Student(Person):
    def __init__(self, indexNr, notes, **kwargs):
        # since Employee comes after Student in the mro, pass its arguments using super
        super().__init__(**kwargs)
        self.indexNr = indexNr
        self.notes = notes

class Employee(Person):
    def __init__(self, salary, position, **kwargs):
        super().__init__(**kwargs)
        self.salary = salary
        self.position = position

class WorkingStudent(Student, Employee):
    def __init__(self, **kwargs):
        # pass all arguments along the mro
        super().__init__(**kwargs)

# keyword arguments (not positional arguments like the case above)
ws = WorkingStudent(name="john", last_name="brown", age=18, indexNr=1, notes=[1,2,3], salary=1000, position='Programmer')

问题:对于最派生的类,我们有很多参数,需要用于初始化所有基类。 但是,在 Python 的带有super()的多重继承系统中,接下来要初始化的类取决于可能已经在另一个类中确定的 MRO(方法解析顺序)。 因此,当我们使用多重继承时,我们不知道使用super()时会调用哪个类的__init__

解决方案:为参数使用一致的名称,然后利用**kwargs ,以便每个类接受它关心的(显式命名的)参数,并转发其余的。

看起来像:

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

class Student(Person):
    def __init__(self, indexNr, notes, **kwargs):
        super().__init__(**kwargs)
        self.indexNr = indexNr
        self.notes = notes

class Employee(Person):
    def __init__(self, salary, position, **kwargs):
        super().__init__(**kwargs)
        self.salary = salary
        self.position = position

class WorkingStudent(Student, Employee):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

强制客户端代码使用关键字参数对客户端来说是更多的工作,但它也有助于防止错误位置参数的顺序错误。

这似乎可行,但并不美观。 我承认我对 Python 中的多重继承并不熟悉,我认为这可能不是最正确的方式。 希望其他人能给出更好的答案。

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


class Student(Person):
    def __init__(self, name, last_name, age, indexNr, notes):
        Person.__init__(self, name, last_name, age)
        self.indexNr = indexNr
        self.notes = notes


class Employee(Person):
    def __init__(self, name, last_name, age, salary, position):
        Person.__init__(self, name, last_name, age)
        self.salary = salary
        self.position = position


class WorkingStudent(Student, Employee):
    def __init__(self, name, last_name, age, indexNr, notes, salary, position):
        Student.__init__(self, name, last_name, age, indexNr, notes)
        Employee.__init__(self, name, last_name, age, salary, position)


ws = WorkingStudent("john", "brown", 18, 1, [1, 2, 3], 1000, 'Programmer')
print(ws)

输出:

<__main__.WorkingStudent object at 0x000002526F11F3D0>

这是实现目标的最简单方法。
如果您的 WorkingStudent 类像这样继承 Student 和 Employee 类,

class WorkingStudent(Student, Employee):
    def __init__(self, name, last_name, age, indexNr, notes, salary, position):
        Student.__init__(self, name, last_name, age, indexNr, notes)
        Employee.__init__(self, name, last_name, age, salary, position)


ws = WorkingStudent("john", "brown", 18, 1, [1, 2, 3], 1000, 'Programmer')
print(ws)
print(ws.name)
print(ws.age)

你的输出将是......

输出:

< 0x7fc6c4d8ba10 处的主要.WorkingStudent 对象>
约翰
18
[1、2、3]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM