继承(三大特性)
# 简介
继承机制经常用于创建和现有类功能类似的新类,又或是新类只需要在现有类基础上添加一些成员(属性和方法),但又不想直接将现有类代码复制给新类。也就是说,通过使用继承这种机制,可以轻松实现类的重复使用。
举个例子,假设现有一个 Shape 类,该类的 draw() 方法可以在屏幕上画出指定的形状,现在需要创建一个 Form 类,要求此类不但可以在屏幕上画出指定的形状,还可以计算出所画形状的面积。要创建这样的类,笨方法是将 draw() 方法直接复制到新类中,并添加计算面积的方法。实现代码如下所示:
class Shape:
def draw(self,content):
print("画",content)
class Form:
def draw(self,content):
print("画",content)
def area(self):
#....
print("此图形的面积为...")
2
3
4
5
6
7
8
9
当然还有更简单的方法,就是使用类的继承机制。
class Shape:
def draw(self,content):
print("画",content)
class Form(Shape):
def area(self):
#....
print("此图形的面积为...")
# 实现方法为:让 From 类继承 Shape 类,这样当 From 类对象调用 draw() 方法时,Python 解释器会先去 From 中找以 draw 为名的方法,如果找不到,它还会自动去 Shape 类中找。如此,我们只需在 From 类中添加计算面积的方法即可
2
3
4
5
6
7
8
9
Python 中,实现继承的类称为子类,被继承的类称为父类(也可称为基类、超类)
子类继承父类时,只需在定义子类时,将父类(可以是多个)放在子类之后的圆括号里即可。语法格式如下:
class 类名(父类1, 父类2, ...):
#类定义部分
2
# 单继承
class 派生类名(基类名)
...
2
在python中子类继承的一些特点:
特点:
- 如果类中不定义__init__,就默认调用父类super class的__init__
- 如果类继承父类,也需要定义自己的__init__,就需要在当前类的__init__调用一下父类的_init__:可以用自己的init
- 如何调用父类__init__: super().init(参数) super(类名,对象).init(参数)
- override:重写,如果子类重写了父类的方式,就调用 子类的方法
- 子类中可以调用父类方法 super().方法名(参数)
- 私有属性,只能在自己的类中访问。但是可以调用父类中使用私有属性的方法。方法中的属性是父类自己的私有属性
class Person: # 父类,基类
def __init__(self, name, age):
self.name = name # 王一
self.age = age # 30
self.__phone = "123"
def run(self):
print("{}跑步中....{}".format(self.name, self.__phone))
def eat(self):
print("{}吃饭中....".format(self.name))
class Student(Person): # 继承了父类,就表示获取了它所有的方法和属性(私有不算)
def __init__(self, name, age, sex): # 差不多是重写了构造方法
super().__init__(name, age) # 使用了父类定义的属性,继承了父类的属性
self.age = 99
self.sex = sex
# 这样出现的是警告,波浪线才是错误
def eat(self, food): # 重写了父类的eat方法,python只有重载,没有重写
super().run() # 调用父类的eat方法
print("student eat - {}正在吃{},{},{}".format(self.name, food, self.sex, self.age))
Person("王一", 30)
stu = Student("李小小", 20, "男")
stu.eat("饭")
print("-------------------" * 2)
"""
李小小跑步中....123
student eat - 李小小正在吃饭,男,99
--------------------------------------
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
子类不能访问父类的私有属性
# 验证子类能不能访问父类的私有属性
# 1.自己的类中只能用自己类中的私有属性
class Person1:
def __init__(self, sex):
self.sex = sex
self.__money = 200
self.name = "abc"
def show1(self):
print("我是父类的show{},{}".format(self.__money, self.name))
class Student2(Person1):
def __init__(self, sex):
super(Student2, self).__init__(sex) # 使用super(),访问父类中的普通属性
self.__money2 = 500 # 私有属性,只可以在本类中访问
self.name = "deg"
super().show1() # 使用super().show1() 访问父类中使用私有属性的方法
def show(self):
print(self.__money2, "------", self.sex) # 访问自己类中的私有属性,不能访问父类的私有属性
class Stu3(Person1):
def __init__(self, sex):
super(Stu3, self).__init__(sex)
def show(self):
print(self.name, "--=-", self.sex) # 访问父类的普通属性
s = Student2("男")
s.show()
s3 = Stu3("女人")
s3.show()
"""
我是父类的show200,deg
500 ------ 男
abc --=- 女人
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 多继承语法
如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。****
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:
class SubClassName (ParentClass1[, ParentClass2, ...]):
...
2
"""
python多继承
A(B,C) 逗号隔开
经典类class A, 新式类:class A(oobject)
但python3中取消了经典类,默认继承object,即python3中class A也是新式类。
"""
# 深度优先:当调用A类test函数时,如下图所示,先查找A类中有无test函数,再查找B类,再查找D类,最后查找C类。 python2
# A-->B-->D-->C
# 广度优先:当调用A类test函数时,如下图所示,先查找A类有无test函数,再查找B类,再查找C类,最后查找D类。 python3
# A-->B-->C-->D
class D: # 默认继承了object
def test(self):
print("D")
class C(D):
def test(self):
print("C")
class B(D):
pass
# def test(self):
# print("B")
class A(B, C):
pass
# def test(self):
# print("A")
a = A()
a.test()
# 查看执行顺序
print(A.__mro__)
import inspect
print(inspect.getmro(A))
"""
C
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
使用多继承经常需要面临的问题是,多个父类中包含同名的类方法。对于这种情况,Python 的处置措施是:根据子类继承多个父类时这些父类的前后次序决定,即排在前面父类中的类方法会覆盖排在后面父类中的同名类方法。
class People:
def __init__(self):
self.name = People
def say(self):
print("People类",self.name)
class Animal:
def __init__(self):
self.name = Animal
def say(self):
print("Animal类",self.name)
#People中的 name 属性和 say() 会遮蔽 Animal 类中的
class Person(People, Animal):
pass
zhangsan = Person()
zhangsan.name = "张三"
zhangsan.say() # People类 张三
# 可以看到,当 Person 同时继承 People 类和 Animal 类时,People 类在前,因此如果 People 和 Animal 拥有同名的类方法,实际调用的是 People 类中的。
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 总结
总结:继承就是子类继承父类
- has a :使用自定义的类型,系统类型
- Is a :子类(父类) ,子类不能继承父类的私有属性,私有属性,可以在自己的类中使用
- 多继承 :广度优先(python3) ,深度优先(python2)
查看执行顺序:对象名.mro 或者import inspect print(inspect.getmro(对象名))
# 重写父类方法
子类继承了父类,那么子类就拥有了父类所有的类属性和类方法。通常情况下,子类会在此基础上,扩展一些新的类属性和类方法。
但凡事都有例外,我们可能会遇到这样一种情况,即子类从父类继承得来的类方法中,大部分是适合子类使用的,但有个别的类方法,并不能直接照搬父类的,如果不对这部分类方法进行修改,子类对象无法使用。针对这种情况,我们就需要在子类中重复父类的方法。
示例
# 举个例子,鸟通常是有翅膀的,也会飞,因此我们可以像如下这样定义个和鸟相关的类:
class Bird:
# 鸟有翅膀
def isWing(self):
print("鸟有翅膀")
# 鸟会飞
def fly(self):
print("鸟会飞")
# 但是,对于鸵鸟来说,它虽然也属于鸟类,也有翅膀,但是它只会奔跑,并不会飞。针对这种情况,可以这样定义鸵鸟类:
class Ostrich(Bird):
# 重写Bird类的fly()方法
def fly(self):
print("鸵鸟不会飞")
# 可以看到,因为 Ostrich 继承自 Bird,因此 Ostrich 类拥有 Bird 类的 isWing() 和 fly() 方法。
# 其中,isWing() 方法同样适合 Ostrich,但 fly() 明显不适合,因此我们在 Ostrich 类中对 fly() 方法进行重写。
ostrich = Ostrich()
ostrich.fly()
ostrich.isWing()
"""
鸵鸟不会飞
鸟有翅膀
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
重写,有时又称覆盖,是一个意思,指的是对类中已有方法的内部实现进行修改。
# 1. 调用被重写的父类方法
Python 中的类可以看做是一个独立空间,而类方法其实就是出于该空间中的一个函数。而如果想要全局空间中,调用类空间中的函数,只需要在调用该函数是备注类名即可。举个例子:
# 调用被重写的父类方法
class Bird:
# 鸟有翅膀
def isWing(self):
print("鸟有翅膀")
# 鸟会飞
def fly(self):
print("鸟会飞")
class Ostrich(Bird):
# 重写Bird类的fly()方法
def fly(self):
print("鸵鸟不会飞")
# 创建Ostrich对象
ostrich = Ostrich()
# 调用 Bird 类中的 fly() 方法
Bird.fly(ostrich)
"""
鸟会飞
"""
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23