Python知识
继承
什么是继承
继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。
子类会“”遗传”父类的属性,从而解决代码重用问题
class Parent1(object):
x = 1111
class Parent2(object):
pass
class Sub1(Parent1): # 单继承
pass
class Sub2(Parent1, Parent2): # 多继承
pass
print(Sub1.x)
'''
1111
'''
python的多继承:
优点:
可以同时遗传多个父类的属性,最大限度地重用代码
缺点:
- 违背人的思维习惯:继承表达的是一种什么“是”什么的关系
- 代码可读性会变差
- 扩展性变差
不建议使用多继承,如果真的设计到一个子类不可避免地重要多个父类的属性,应该使用Mixins机制
如何实现继承
没学继承前定义类,会出现代码冗余的问题
class Student:
school = '广师大'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def choose_course(self):
print('%s 正在选课' % self.name)
class Teacher:
school = '广师大'
def __init__(self, name, age, gender, salary, level):
self.name = name
self.age = age
self.gender = gender
self.salary = salary
self.level = level
def score(self):
print('%s老师 正在给学生打分' % self.name)
通过继承方法:
class School:
school = '广师大'
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Student(School):
def choose_course(self):
print('%s 正在选课' % self.name)
class Teacher(School):
def __init__(self, name, age, gender, salary, level):
School.__init__(self, name, age, gender)
self.salary = salary
self.level = level
def score(self):
print('%s老师 正在给学生打分' % self.name)
单继承背景下的属性查找
请问一下输出的结果是?
class Foo:
def f1(self):
print('foo.f1')
def f2(self):
print('foo.f2')
self.f1()
class Bar(Foo):
def f1(self):
print('bar.f1')
obj = Bar()
obj.f2()
答案是:
foo.f2
bar.f1
为何是这样的输出结果?
obj.f2()
首先输出foo.f2
很好理解,对象本身属性查找,会向类进行查找,如果找不到,就向父类进行查找,但是它的对象名始终是obj
,所以在f2中的self.f1()
,对象依然是obj.f1()
,所以结果是bar.f1
如果想让f2中的self.f1()
查找的是父类中的f1,有两种方法
第一种:直接将对象名更改成父类
def f2(self):
print('foo.f2')
Foo.f1()
第二种:利用隐藏属性
def __f1(self): #变形为 __Foo__f1
print('foo.f1')
def f2(self):
print('foo.f2')
self.__f1()
foo.f2
foo.f1
菱形问题与MRO介绍
大多数面向对象语言都不支持多继承,而在Python中,一个子类是可以同时继承多个父亲的,这固然可以的带来一个子类可以对不同父类加以重用的好处,但也有可能引发菱形问题,菱形问题其实就是对下面这种继承结构的形象比喻
class A:
def test(self):
print('from A')
class B(A):
def test(self):
print('from B')
class C(A):
def test(self):
print('from C')
class D(B, C):
pass
obj = D()
obj.test()
'''
from B
'''
python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如:
print(D.mro()) # 类以及该类的对象访问属性都是参照该类的mro列表
'''
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>,
<class 'object'>]
'''
为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:
- 子类会先于父类被检查
- 多个父类会根据它们在列表中的顺序被检查
- 如果对下一个类存在两个合法的选择,选择第一个父类