如何创建多个继承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
注意:我已经完成了多个 Whosebug 查询,但我找不到任何可以回答这个问题的东西。 (也许我错过了)。
这似乎可行,但并不美观。我承认我对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>
而不是显式 classes,使用 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.
检查 mro:
WorkingStudent.__mro__
(__main__.WorkingStudent,
__main__.Student,
__main__.Employee,
__main__.Person,
object)
创建 WorkingStudent 的实例时,最好传递关键字参数,这样您就不必担心弄乱参数的顺序。
由于 WorkingStudent 将属性的定义推迟到父级 classes,立即使用 super().__init__(**kwargs)
将所有参数向上传递到层次结构中,因为子级 class 不需要知道它不处理的参数。第一个父 class 是学生,因此 self.IndexNr 等在那里定义。 mro 中的下一个父 class 是 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')
问题:我们最派生的 class 有很多参数,需要用于初始化所有基数。但是,在 Python 的多重继承系统中 super()
,接下来要初始化的 class 取决于一个 MRO(方法解析顺序),这个 MRO(方法解析顺序)可能已经在另一个 class.因此,当我们使用多重继承时,我们不知道当我们使用super()
时,哪个class会调用它的__init__
。
解决方法:对参数使用一致的名字,然后利用**kwargs
,这样每个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, 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)
强制客户端代码使用关键字参数对客户端来说是一项更多的工作,但它也有助于防止因弄错位置参数的顺序而导致的错误。
这是实现目标的最简单方法。
如果您的 WorkingStudent class 像这样继承 Student 和 Employee class,
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)
你的输出将是...
输出:
<main.WorkingStudent object at 0x7fc6c4d8ba10>
john
18
[1, 2, 3]
我有这个代码:
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
注意:我已经完成了多个 Whosebug 查询,但我找不到任何可以回答这个问题的东西。 (也许我错过了)。
这似乎可行,但并不美观。我承认我对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>
而不是显式 classes,使用 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.
检查 mro:
WorkingStudent.__mro__
(__main__.WorkingStudent,
__main__.Student,
__main__.Employee,
__main__.Person,
object)
创建 WorkingStudent 的实例时,最好传递关键字参数,这样您就不必担心弄乱参数的顺序。
由于 WorkingStudent 将属性的定义推迟到父级 classes,立即使用 super().__init__(**kwargs)
将所有参数向上传递到层次结构中,因为子级 class 不需要知道它不处理的参数。第一个父 class 是学生,因此 self.IndexNr 等在那里定义。 mro 中的下一个父 class 是 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')
问题:我们最派生的 class 有很多参数,需要用于初始化所有基数。但是,在 Python 的多重继承系统中 super()
,接下来要初始化的 class 取决于一个 MRO(方法解析顺序),这个 MRO(方法解析顺序)可能已经在另一个 class.因此,当我们使用多重继承时,我们不知道当我们使用super()
时,哪个class会调用它的__init__
。
解决方法:对参数使用一致的名字,然后利用**kwargs
,这样每个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, 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)
强制客户端代码使用关键字参数对客户端来说是一项更多的工作,但它也有助于防止因弄错位置参数的顺序而导致的错误。
这是实现目标的最简单方法。
如果您的 WorkingStudent class 像这样继承 Student 和 Employee class,
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)
你的输出将是...
输出:
<main.WorkingStudent object at 0x7fc6c4d8ba10>
john
18
[1, 2, 3]