[python相关]多类继承中子类默认继承哪个父类的构造函数__init__

本文探讨了Python中多继承情况下子类构造函数的工作原理。当子类未定义构造函数时,将根据父类的顺序继承第一个有构造函数的父类构造函数。文章详细解释了这一过程,并给出了明确的继承规则。

【1】python中如果子类有自己的构造函数,不会自动调用父类的构造函数,如果需要用到父类的构造函数,则需要在子类的构造函数中显式的调用。

 

【2】如果子类没有自己的构造函数,则会直接从父类继承构造函数,这在单继承(一个子类只从一个父类派生)中没有任何理解上的问题。

         问题:如果是多继承的情况,一个子类从多个父类派生,而子类又没有自己的构造函数,则子类默认会继承哪个父类的构造函数。

 

【3】子类从多个父类派生,而子类又没有自己的构造函数时,

(1)按顺序继承,哪个父类在最前面且它又有自己的构造函数,就继承它的构造函数;

(2)如果最前面第一个父类没有构造函数,则继承第2个的构造函数,第2个没有的话,再往后找,以此类推。

在面向对象编程中,继承是一种使得子类能够获取父类的属性和方法的机制。Python支持继承,并提供了灵活的方式来继承和扩展的功能。以下是关于Python中子继承父类的详细介绍: ### 基本概念 父类(基)是被继承子类(派生)是继承父类[^1]。 ### 实现继承 #### 子类继承父类的三种情况 1. **直接继承不重写 `__init__` 方法**:子类直接继承父类的所有属性和方法,不覆盖父类的 `__init__` 方法。 ```python class Person: def __init__(self, name="person"): self.name = name class Puple(Person): # sub class1 pass pp = Puple() print(pp.name) # 输出: person ``` 在这个例子中,`Puple` 继承了 `Person` 没有重写 `__init__` 方法,所以 `Puple` 的实例 `pp` 拥有 `Person` 的 `name` 属性,并且值为默认值 `"person"`。 2. **重写 `__init__` 方法但不继承父类属性**:子类重写了父类的 `__init__` 方法,会丢失父类中定义的属性。 ```python class Person: def __init__(self, name="person"): self.name = name class Puple_Init(Person): # sub class2 def __init__(self, age): # 覆盖父类中的__init__ 方法,丢失父类中self.name 属性 self.age = age pp_i = Puple_Init(10) # 下面这行代码会报错,因为 Puple_Init 实例没有 name 属性 # print(pp_i.name) ``` 在这个例子中,`Puple_Init` 重写了 `__init__` 方法,只定义了 `age` 属性,丢失了父类的 `name` 属性。 3. **重写 `__init__` 方法并继承父类属性**:子类重写 `__init__` 方法,同时使用 `super` 关键字调用父类的 `__init__` 方法来继承父类的属性。 ```python class Person: def __init__(self, name="person"): self.name = name class Puple_Super(Person): # sub class3 def __init__(self, name, age): # 重载父类中 __init__ 方法 self.age = age # 并继承父类中self.name 属性 super(Puple_Super, self).__init__(name) pp_s = Puple_Super("puple_super", 13) print(pp_s.name, pp_s.age) # 输出: puple_super 13 ``` 在这个例子中,`Puple_Super` 重写了 `__init__` 方法,通过 `super(Puple_Super, self).__init__(name)` 调用父类的 `__init__` 方法,传入 `name` 参数,从而继承父类的 `name` 属性,同时定义了自己的 `age` 属性。 ### 子类调用父类构造函数的方法 子类如果重写了 `__init__`,并且要继承父类的构造方法,可以使用以下几种方式: 1. **`super(子类, self).__init__(参数1,参数2,....)`**:这是 Python 2 中常用的方式,在 Python 3 中也兼容。 ```python class Father(object): def __init__(self, name): self.name = name print("name: %s" % (self.name)) def getName(self): return "Father " + self.name class Son(Father): def __init__(self, name): super(Son, self).__init__(name) print("hi") self.name = name def getName(self): return "Son " + self.name son = Son("runoob") print(son.getName()) ``` 在这个例子中,`Son` 重写了 `__init__` 方法,通过 `super(Son, self).__init__(name)` 调用父类的 `__init__` 方法,传入 `name` 参数。 2. **`super().__init__(继承父类的属性参数)`**:这是 Python 3 中推荐的方式,更加简洁。 ```python class Father: def __init__(self, name): self.name = name class Son(Father): def __init__(self, name): super().__init__(name) self.age = 20 son = Son("John") print(son.name) # 输出: John ``` 在这个例子中,`Son` 重写了 `__init__` 方法,使用 `super().__init__(name)` 调用父类的 `__init__` 方法。 3. **`父类名.__init__(self, 继承父类的属性参数)`**:这种方式不推荐使用,因为当父类名改变或者涉及多重继承时,代码的维护成本较高。 ```python class Father: def __init__(self, name): self.name = name class Son(Father): def __init__(self, name): Father.__init__(self, name) self.age = 20 son = Son("John") print(son.name) # 输出: John ``` 在这个例子中,`Son` 重写了 `__init__` 方法,使用 `Father.__init__(self, name)` 调用父类的 `__init__` 方法。 ### 子类重写父类方法 子类可以重写父类的方法,以实现自己的特定逻辑。在子类中定义与父类同名的方法,就会覆盖父类的方法。 ```python class Aniaml: def walk(self): print("走") class Dog(Aniaml): # 改写继承父类的方法 # 子类方法名、参数应该和父类方法一样 def walk(self): # super 可以调用继承父类的同名方法 super().walk() print("跑") # 增加新方法 def bark(self): print("汪汪") dog = Dog() dog.walk() # 输出: 走 跑 dog.bark() # 输出: 汪汪 ``` 在这个例子中,`Dog` 继承了 `Aniaml` ,重写了 `walk` 方法,在重写的方法中使用 `super().walk()` 调用父类的 `walk` 方法,然后添加了自己的逻辑。同时,`Dog` 还新增了 `bark` 方法。 ### 相关问题 1. 多重继承时,`super` 关键字的调用顺序是怎样的? 2. 子类继承父类的私有属性和方法有什么特殊规则? 3. 当父类子类的方法名相同但参数不同时,会发生什么? 4. 如何在子类中调用父类的静态方法和方法?
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值