204-面向对象三大特性-2.继承
三种特性:
- 封装性:
- 私有属性和私有方法
- 把属性和方法隐藏起来,属性没有特殊要求都用私有属性
- 意义:
- 以面向对象的编程思想进行项目开发
- 封装数据属性:明确的区分内外,控制外部对隐藏的属性的操作行为(保护数据、过滤掉异常数据)
- 继承性:
- 单继承和多继承
- 多态性
2、python中的继承
什么是继承
我们接下来来聊聊Python代码中的“继承”:类是用来描述现实世界中同一组事务的共有特性的抽象模型,但是类也有上下级和范围之分,比如:生物 => 动物
继承的基本语法
假设A类要继承B类中的所有属性和方法(私有属性和私有方法除外)
class B(object):
pass
class A(B):
pass
a = A()
a.B中的所有公共属性
a.B中的所有公共方法
相关名词解释
继承:一个类从另一个已有的类获得其成员的相关特性,就叫作继承!
派生:从一个已有的类产生一个新的类,称为派生!
很显然,继承和派生其实就是从不同的方向来描述的相同的概念而已,本质上是一样的!
父类:也叫作基类,就是指已有被继承的类!
子类:也叫作派生类或扩展类
扩展:在子类中增加一些自己特有的特性,就叫作扩展,没有扩展,继承也就没有意义了!
单继承:一个类只能继承自一个其他的类,不能继承多个类,单继承也是大多数面向对象语言的特性!
多继承:一个类同时继承了多个父类, (C++、Python等语言都支持多继承)
单继承
一个类只能继承自一个其他的类,不能同时继承多个类。这个类会有具有父类的属性和方法。
基本语法:
# 1、定义一个共性类(父类)
class Person(object):
pass
# 2、定义一个个性类(子类)
class Student(Person):
pass
栗子:
# 定义一个公共类
class Person(object):
def speak(self):
print('i can speak')
# 定义学生
class Student(Person):
pass
# 定义ikun
class Ikun(Person):
pass
ZhangSan = Student()
ZhangSan.speak()
单继承特性(多层继承):传递性
在Python继承中,如A类继承了B类,B类又继承了C类。则根据继承的传递性,则A类也会自动继承C类中所有属性和方法(公共)
class C(object):
def func(self):
print('我是C类中的相关方法func')
class B(C):
pass
class A(B):
pass
a = A()
a.func()
多继承
Python语言是少数支持多继承的一门编程语言,所谓的多继承就是允许一个类同时继承自多个类的特性。
基本语法:
class B(object):
pass
class C(object):
pass
class A(B, C):
pass
a = A()
a.B中的所有属性和方法
a.C中的所有属性和方法
栗子:
# 定义黑子
class HeiZi(object):
def speak(self):
print('我们家哥哥')
# 定义ikun
class Ikun(Person):
def speak(self):
print('你干嘛~嗨嗨哎呦')
class ZhenAiFen(Ikun, Heizi):
pass
ZhangSan = ZhenAiFen()
ZhangSan.speak()
注意:虽然多继承允许我们同时继承自多个类,但是实际开发中,应尽量避免使用多继承,因为如果两个类中出现了相同的属性和方法就会产生命名冲突。
上面代码中,继承的两个类中都有speak方法,但是子类只调用了Ikun
的的speak方法,没有调用HeiZi的speak方法,这里就涉及到方法解析顺序,一般的优先级是:本类中定义的方法>排在前面的父类中的方法
super()调用父类属性和方法
super():调用父类属性或方法,完整写法:super(当前类名, self).属性或方法()
,在Python3以后版本中,调用父类的属性和方法我们只需要使用super().属性或super().方法名()
就可以完成调用了。
案例:Car汽车类、GasolineCar汽油车、ElectricCar电动车
class Car(object):
def __init__(self, brand, model, color):
self.brand = brand
self.model = model
self.color = color
def run(self):
print('i can run')
class GasolineCar(Car):
def run(self):
print('i can run with gasoline')
class ElectricCar(Car):
def __init__(self, brand, model, color, battery):
super().__init__(brand, model, color)
# 电池属性
self.battery = battery
def run(self):
print(f'i can run with electric,i have a {self.battery} + "kwh battery"')
bwm = GasolineCar('宝马', 'X5', '白色')
bwm.run()
tesla = ElectricCar('特斯拉', 'Model S', '红色', 70)
tesla.run()
### MRO属性或MRO方法:方法解析顺序
MRO(Method Resolution Order):方法解析顺序,我们可以通过`类名.__mro__`或`类名.mro()`获得“类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找到。
```python
class Car(object):
def __init__(self, brand, model, color):
self.brand = brand
self.model = model
self.color = color
def run(self):
print('i can run')
class GasolineCar(Car):
def run(self):
print('i can run with gasoline')
class ElectricCar(Car):
def __init__(self, brand, model, color, battery):
super().__init__(brand, model, color)
# 电池属性
self.battery = battery
def run(self):
print(f'i can run with electric,i has a {self.battery} + "kwh battery"')
print(ElectricCar.__mro__)
print(ElectricCar.mro())
代码的输出是:
D:\Python\Python37\python.exe D:/PycharmProjects/pythonProject/07-Python中的MR0方法解析顺序.py
(<class '-_main-_.ElectricCar'>, <class '-_main__.Car'>, <class 'object'>)
[<class '--main_-.Electriccar'>, <class '--main--.Car'>, <class 'object'>]]
说明:有MRO方法解析顺序可知,在类的继承中,当某个类创建了一个对象时,调用属性或方法,首先在自身类中去寻找,如找到,则直接使用,停止后续的查找。如果未找到,继续向上一级继承的类中去寻找,如找到,则直接使用,没有找到则继续向上寻找...直到object类,这就是Python类继承中,其方法解析顺序。
综上:object类还是所有类的基类(因为这个查找关系到object才终止)
常见问题
问题1:在定义类时,其没有遵循类的命名规则
答:在Python中,类理论上是区分大小写的(在Python中类可以全部大写也可以全部小写)。但是要遵循一定的命名规范:首字母必须是字母或下划线,其中可以包含字母、数字和下划线,而且要求其命名方式采用大驼峰。
电动汽车:EletricCar
父类:Father
子类:Son
问题2:父类一定要继承object么?Car(object)
答:在Python面向对象代码中,建议在编写父类时,让其自动继承object类。但是其实不写也可以,因为默认情况下,Python中的所有类都继承自object。
问题3:打印属性和方法时,不是只能使用print()函数输出,也可以使用return。
在实际打印对象信息,还建议使用__str__
class Person():
def __init__(self, name):
self.name = name
def speak(self):
print('i can speak')
# 创建对象,打印属性和方法
p = Person('Tom')
print(p.name)
p.speak()
问题4:在定义魔术方法__init__
而非__int__