大家好,给大家分享一下笨办法学python 3电子书下载,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!
Source code download: 本文相关源码
练习44 继承和组合
永远记住这一点:继承的大多数用法都可以用组合(composition)来简化或替换。并且无论如何都要避免多重继承python自学可行吗。
内容提要:
1. 什么是继承?
(1)隐式继承
(2)显示继承
(3)改变前后
(4)三种组合
(5)为何用super()
(6)组合
2. 何时使用继承和组合
什么是继承?
继承用来表明一个类将从其父类那里获得大多数或所有特性。当你在做这种专门化时,有三种父类和子类可以交互的方法:
(1)对子类的行为意味着对父类的行为。——隐式继承
(2)子类上的操作会覆盖父类上的操作。——显示继承
(3)子类上的操作会更改父类上的操作。
1、隐式继承
代码:ex44a.py
class Parent(object): #创建父类
def implicit(self): #创建函数
print("PARENT implicit()")
class Child(Parent): #创建子类Child,继承至父类Parent
pass
dad = Parent() #Parent()类实例化
son = Child() #Child()类实例化
dad.implicit() #调用父类内部函数
son.implicit() #调用函数继承至父类
输出结果:
PARENT implicit()
PARENT implicit()
说明:
pass关键词:“暂时跳过”,pass 是一种空操作,解释器执行到它的时候,除了检查语法是否合法,什么也不做就直接跳过。使用在函数、类、循环体或者条件判断语句中。用于补充语法的完整性,要不然代码会报错。
Child()的类底下使用pass空块,没有定义实际内容,但它仍旧可以可以调用函数implicit(),就是因为它继承了父类Parent()的函数,这就是隐式继承。因此如果将函数放在父类中(比如 Parent),然后所有子类(比如 Child)会自动获得这些特性。对于需要写很多重复代码的类来说非常方便。
2、显式继承
代码:ex44b.py
#显式继承——子类中定义一个与父类同名的函数,以替换父类中的函数功能
class Parent(): #创建父类
def override(self): #创建父类的函数
print("Parent override()")
class Child(Parent): #创建子类Child继承至父类Parent
def override(self): #创建与父类中函数同名的函数,但功能与其不同
print("Child override()")
dad = Parent() #实例化父类
son = Child() #实例化子类
dad.override() #调用父类中的函数override()
son.override() #调用子类中的函数override()
输出结果:
Parent override()
Child override()
说明:
隐式调用函数的问题在于,有时希望子类与父类的行为有所不同。**只需要在子类( Child) 中定义一个与父类(Parent)同名函数,子类上的操作会覆盖父类上的操作。**如上代码中,父类与子类都同时存在的override()函数,运行之后的结果不同。
3、修改前后
代码:ex44c.py
#子类上的操作会更改父类上的操作
#修改类中函数前后
class Parent(): #创建父类
def altered(self): #创建父类函数
print("Parent altered()")
class Child(Parent): #创建子类
def altered(self): #创建与父类函数同名的子类函数,覆盖父类函数
print("Child, Before Parent altered()") #打印
super().altered() #利用super(超类)调用父类中的函数
print("Child, After Parent altered()") #继续打印
dad = Parent() #实例化父类
son = Child() #实例化子类
dad.altered() #调用父类函数
son.altered() #调用子类函数
输出结果:
Parent altered()
Child, Before Parent altered()
Parent altered()
Child, After Parent altered()
说明:
第三种使用继承的方式是覆盖的一种特殊情况,可以在父类版本运行前后更改子类的函数内容。首先,与之前一样在子类中创建一个与父类同名的函数,覆盖原先的函数;其次使用super()函数调用父类中的函数。
4、以上三中继承形式结合
过一遍这段代码的每一行,并每一行加上注释,说明它的作用。
#三者结合
class Parent(): #创建父类
def override(self): #创建父类函数override
print("Parent override()") #函数的行为,打印字符串
def implicit(self): #创建父类函数implicit()
print("Parent implicit()") #函数的行为,打印字符串
def altered(self): #创建父类函数altered()
print("Parent altered()") #函数的行为,打印字符串
class Child(Parent): #创建子类
def override(self): #创建与父类中override同名的函数,覆盖父类中该函数的内容
print("Child override()")
def altered(self): #创建与父类中altered同名函数,覆盖父类该函数内容
print("Child, Before Parent altered()")
super().altered() #调用函数super(超类),再次继承父类中的函数altered()
print("Child, After Parent altered()")
dad = Parent() #父类实例化
son = Child() #子类实例化
dad.implicit() #调用父类函数implicit()
son.implicit() #子类中未定义函数implicit(),但隐式继承了父类,也可调用该函数,且内容相同
dad.override() #调用父类override()函数
son.override() #调用子类override()函数
dad.altered() #调用父类altered()函数
son.altered() #调用子类altered()函数
输出结果:
Parent implicit()
Parent implicit()
Parent override()
Child override()
Parent altered()
Child, Before Parent altered()
Parent altered()
Child, After Parent altered()
5、用super()的理由
什么是多重继承?(之前练习有学习了解)
如下代码:
class SuperFun(Child, BadStuff):
pass
如上代码中创建的类SuperFun(),同时继承自Child()和BadStuff()两个类,即一个类继承了一个或多个类就是“多重继承”。
在出现多重继承的情况下,对任何 SuperFun 的实例执行隐式操作时,Python 都必须在 Child 类和 BadStuff 类的层级结构中查找可能的函数,不过它需要以一致的顺序来执行这项操作。为了做到这一点,Python 使用了“方法解析顺序”(method resolution order,MRO)和一种被称为 C3 的算法,这种算法很复杂,因此使用super()函数可以帮助我们在需要修改的地方进行处理即可。
用__init__来使用super()
super() 最常用的用法其实是在子类中使用基类的 init 函数。这通常是你在一个子类中唯一需要做一些操作,然后在父类中完成初始化的地方。
示例如下:
class Child(Parent):
def __init__(self, stuff): #初始化函数
self.stuff = stuff
super(Child,self).__init__() #调用父类的初始化函数
6、组合
继承很有用,但是还有一种能实现相同效果的方法,就是使用其他类和模块,而不是依赖于隐式继承。当使用继承时,子类中存在大量的编写新代码来替换或者更改函数功能的时候,可以通过调用模块中的函数来实现。示例如下:
代码ex44e.py
class Other(): #创建一个额外的类Other()
def override(self): #创建函数
print("Other override()")
def implicit(self): #创建类的函数
print("Other implicit()")
def altered(self): #创建类的函数
print("Other altered()")
class Child(): #创建类Child()
# def __init__(self): #创建初始化函数
#创建Other()类与Child()之间的桥梁,也可以没有,但是调用Other()类中的函数方式会有所不用
# self.other = Other()
def implicit(self): #创建函数implicit()
# self.other.implicit() #对应第一种,调用Other()类中的implicit()函数
Other().implicit() #对应第二种,调用Other()类中的implicit()函数
def override(self): #创建函数override()
print("Child override()")
def altered(self): #创建altered()函数
print("Child, Before Other altered()")
# self.other.altered() #第一种,调用Other()类中的altered()函数
Other().altered() #第二种,调用Other()类中的函数altered()
print("Child, After Other altered()")
son = Child() #实例化Child类
son.implicit() #调用函数implicit()
son.override() #调用函数override()
son.altered() #调用函数altered()
输出结果:
Other implicit()
Child override()
Child, Before Other altered()
Other altered()
Child, After Other altered()
说明:
可以看到,Child 和 Other 中的大多数代码都是相同的,可以完成相同的事情。唯一的区别是必须定义一个 Child.implicit 函数来完成这个动作。
其中在Child()类中调用Other()类的方法有两种。
第一种,在Child类的__init__函数中定义other属性,self.other = Other()
,后续可直接使用self.other.函数名
来调用Other类中的函数。
第二种,直接在Child类中,实例化Other类后调用,例如:Other().implicit()
问题:是否可以将Other类放入Other.py的模块中,去调用它?
可以,代码如下:
文件:other.py
class Other(): #创建一个额外的类Other()
def override(self): #创建函数
print("Other override()")
def implicit(self): #创建类的函数
print("Other implicit()")
def altered(self): #创建类的函数
print("Other altered()")
文件:ex44_Child.py
from other import Other #从模块Other中调用Other类
class Child(): #创建类Child()
def __init__(self): #创建初始化函数
#创建Other()类与Child()之间的桥梁,也可以没有,但是调用Other()类中的函数方式会有所不用
self.other = Other()
def implicit(self): #创建函数implicit()
self.other.implicit() #对应第一种,调用Other()类中的implicit()函数
# Other().implicit() #对应第二种,调用Other()类中的implicit()函数
def override(self): #创建函数override()
print("Child override()")
def altered(self): #创建altered()函数
print("Child, Before Other altered()")
self.other.altered() #第一种,调用Other()类中的altered()函数
# Other().altered() #第二种,调用Other()类中的函数altered()
print("Child, After Other altered()")
son = Child() #实例化Child类
son.implicit() #调用函数implicit()
son.override() #调用函数override()
son.altered() #调用函数altered()
输出结果:
Other implicit()
Child override()
Child, Before Other altered()
Other altered()
Child, After Other altered()
说明:
可以通过other.py文件调用Other类,只需要在ex44_Child.py 文件的脚本代码中加入import调用模块,即from other import Other
。在Child类中的调用方式与之前完全相同。
7、何时使用继承和组合
“继承与组合”的问题可以归结为试图解决可复用代码的问题。
——继承通过在父类中创建隐含相同功能的函数的机制来解决这个问题。
——组合通过提供模块以及调用其他类中的函数来解决这个问题。
三个指导方针(建议,但可能无法遵守):
1、无论如何都要避免多重继承,因为它太复杂而且不可靠。
2、使用组合将代码打包到模块中,这些模块可以用于许多不同的、不相关的地方和情境。
3、代码的可复用部分之间有清楚的关联(很明显的父类与子类关系,如动物和猫)或者必须要用继承时,用继承。
附加练习
阅读 : http://www.python.org/dev/peps/pep-0008/ 文件(该网站需要翻墙)。