Skip to content

Commit e35da9c

Browse files
committed
class 4
1 parent 6c72b9a commit e35da9c

5 files changed

Lines changed: 296 additions & 0 deletions

File tree

209.md

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
>你们仍是属肉体的,因为在你们中间有嫉妒分争,这岂不是属乎肉体,照着世人的样子行吗?...我栽种了,亚波罗浇灌了,惟有神叫他生长。(1 CORINTHIANS 3:3,6)
2+
3+
#类(4)
4+
5+
本节介绍类中一个非常重要的东西——继承,其实也没有那么重要,只是听起来似乎有点让初学者晕头转向,然后就感觉它属于很高级的东西,真是情况如何?学了之后你自然有感受。
6+
7+
在现实生活中,“继承”意味着一个人从另外一个人那里得到了一些什么,比如“继承革命先烈的光荣传统”、“某人继承他老爹的万贯家产”等。总之,“继承”之后,自己就在所继承的方面省力气、不用劳神费心,能轻松得到,比如继承了万贯家产,自己就一夜之间变成富豪。如果继承了“革命先烈的光荣传统”,自己是不是一下就变成革命者呢?
8+
9+
当然,生活中的继承或许不那么严格,但是编程语言中的继承是有明确规定和稳定的预期结果的。
10+
11+
>继承(Inheritance)是面向对象软 件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”,也可以称“B是A的超类”。
12+
13+
>继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。 (源自维基百科)
14+
15+
由上面对继承的表述,可以简单总结出继承的意图或者好处:
16+
17+
- 可以实现代码重用,但不是仅仅实现代码重用,有时候根本就没有重用
18+
- 实现属性和方法继承
19+
20+
诚然,以上也不是全部,随着后续学习,对继承的认识会更深刻。好友令狐虫曾经这样总结继承:
21+
22+
>从技术上说,OOP里,继承最主要的用途是实现多态。对于多态而言,重要的是接口继承性,属性和行为是否存在继承性,这是不一定的。事实上,大量工程实践表明,重度的行为继承会导致系统过度复杂和臃肿,反而会降低灵活性。因此现在比较提倡的是基于接口的轻度继承理念。这种模型里因为父类(接口类)完全没有代码,因此根本谈不上什么代码复用了。
23+
24+
>在Python里,因为存在Duck Type,接口定义的重要性大大的降低,继承的作用也进一步的被削弱了。
25+
26+
>另外,从逻辑上说,继承的目的也不是为了复用代码,而是为了理顺关系。
27+
28+
他是大牛,或许读者感觉比较高深,没关系,随着你的实践经验的积累,你也能对这个问题有自己独到的见解。
29+
30+
或许你也要问我的观点是什么?我的观点就是:走着瞧!怎么理解?继续向下看,只有你先深入这个问题,才能跳到更高层看这个问题。小马过河的故事还记得吧?只有亲自走入河水中,才知道河水的深浅。
31+
32+
对于python中的继承,前面一直在使用,那就是我们写的类都是新式类,所有新式类都是继承自object类。不要忘记,新式类的一种写法:
33+
34+
class NewStyle(object):
35+
pass
36+
37+
这就是典型的继承。
38+
39+
##基本概念
40+
41+
#!/usr/bin/env python
42+
# coding=utf-8
43+
44+
__metaclass__ = type
45+
46+
class Person:
47+
def speak(self):
48+
print "I love you."
49+
50+
def setHeight(self, n):
51+
self.length = n
52+
53+
def breast(self, n):
54+
print "My breast is: ",n
55+
56+
class Girl(Person):
57+
def setHeight(self):
58+
print "The height is:1.70m ."
59+
60+
if __name__ == "__main__":
61+
cang = Girl()
62+
cang.setHeight()
63+
cang.speak()
64+
cang.breast(90)
65+
66+
上面这个程序,保存之后运行:
67+
68+
$ python 20901.py
69+
The height is:1.70m .
70+
I love you.
71+
My breast is: 90
72+
73+
对以上程序进行解释,从中体会继承的概念和方法。
74+
75+
首先定义了一个类Person,在这个类中定义了三个方法。注意,没有定义初始化函数,初始化函数在类中不是必不可少的。
76+
77+
然后又定义了一个类Girl,这个类的名字后面的括号中,是上一个类的名字,这就意味着Girl继承了Person,Girl是Person的子类,Person是Girl的父类。
78+
79+
既然是继承了Person,那么Girl就全部拥有了Person中的方法和属性(上面的例子虽然没有列出属性)。但是,如果Girl里面有一个和Person同样名称的方法,那么就把Person中的同一个方法遮盖住了,显示的是Girl中的方法,这叫做方法的**重写**
80+
81+
实例化类Girl之后,执行实例方法`cang.setHeight()`,由于在类Girl中重写了setHeight方法,那么Person中的那个方法就不显作用了,在这个实例方法中执行的是类Girl中的方法。
82+
83+
虽然在类Girl中没有看到speak方法,但是因为它继承了Person,所以`cang.speak()`就执行类Person中的方法。同理`cang.breast(90)`,它们就好像是在类Girl里面已经写了这两个方法一样。既然继承了,就是我的了。
84+
85+
##多重继承
86+
87+
所谓多重继承,就是只某一个类的父类,不止一个,而是多个。比如:
88+
89+
#!/usr/bin/env python
90+
# coding=utf-8
91+
92+
__metaclass__ = type
93+
94+
class Person:
95+
def eye(self):
96+
print "two eyes"
97+
98+
def breast(self, n):
99+
print "The breast is: ",n
100+
101+
class Girl:
102+
age = 28
103+
def color(self):
104+
print "The girl is white"
105+
106+
class HotGirl(Person, Girl):
107+
pass
108+
109+
if __name__ == "__main__":
110+
kong = HotGirl()
111+
kong.eye()
112+
kong.breast(90)
113+
kong.color()
114+
print kong.age
115+
116+
在这个程序中,前面有两个类:Person和Girl,然后第三个类HotGirl继承了这两个类,注意观察继承方法,就是在类的名字后面的括号中把所继承的两个类的名字写上。但是第三个类中什么方法也没有。
117+
118+
然后实例化类HotGirl,既然继承了上面的两个类,那么那两个类的方法就都能够拿过来使用。保存程序,运行一下看看
119+
120+
$ python 20902.py
121+
two eyes
122+
The breast is: 90
123+
The girl is white
124+
28
125+
126+
值得注意的是,这次在类Girl中,有一个`age = 28`,在对HotGirl实例化之后,因为继承的原因,这个类属性也被继承到HotGirl中,因此通过实例属性`kong.age`一样能够得到该数据。
127+
128+
由上述两个实例,已经清楚看到了继承的特点,即将父类的方法和属性全部承接到子类中;如果子类重写了父类的方法,就使用子类的该方法,父类的被遮盖。
129+
130+
##super函数
131+
132+
对于初始化函数的继承,跟一般方法的继承,还有点不同。可以看下面的例子:
133+
134+
#!/usr/bin/env python
135+
# coding=utf-8
136+
137+
__metaclass__ = type
138+
139+
class Person:
140+
def __init__(self):
141+
self.height = 160
142+
143+
def about(self, name):
144+
print "{} is about {}".format(name, self.height)
145+
146+
class Girl(Person):
147+
def __init__(self):
148+
self.breast = 90
149+
150+
def about(self, name):
151+
print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
152+
153+
if __name__ == "__main__":
154+
cang = Girl()
155+
cang.about("canglaoshi")
156+
157+
在上面这段程序中,类Girl继承了类Person。在类Girl中,初始化设置了`self.breast = 90`,由于继承了Person,按照前面的经验,Person的初始化函数中的`self.height = 160`也应该被Girl所继承过来。然后在重写的about方法中,就是用`self.height`
158+
159+
实例化类Girl,并执行`cang.about("canglaoshi")`,试图打印出一句话`canglaoshi is a hot girl, she is about 160, and her bereast is 90`。保存程序,运行之:
160+
161+
$ python 20903.py
162+
Traceback (most recent call last):
163+
File "20903.py", line 22, in <module>
164+
cang.about("canglaoshi")
165+
File "20903.py", line 18, in about
166+
print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
167+
AttributeError: 'Girl' object has no attribute 'height'
168+
169+
报错!
170+
171+
程序员有一句名言:不求最好,但求报错。报错不是坏事,是我们长经验的时候,是在告诉我们,那么做不对。
172+
173+
重要的是看报错信息。就是我们要打印的那句话出问题了,报错信息显示`self.height`是不存在的。也就是说类Girl没有从Person中继承过来这个属性。
174+
175+
原因是什么?仔细观察类Girl,会发现,除了刚才强调的about方法重写了,`__init__`方法,也被重写了。不要认为它的名字模样奇怪,就不把它看做类中的方法(函数),它跟类Person中的`__init__`重名了,也同样是重写了那个初始化函数。
176+
177+
这就提出了一个问题。因为在子类中重写了某个方法之后,父类中同样的方法被遮盖了。那么如何再把父类的该方法调出来使用呢?纵然被遮盖了,应该还是存在的,不要浪费了呀。
178+
179+
python中有这样一种方法,这种方式是被提倡的方法:super函数。
180+
181+
#!/usr/bin/env python
182+
# coding=utf-8
183+
184+
__metaclass__ = type
185+
186+
class Person:
187+
def __init__(self):
188+
self.height = 160
189+
190+
def about(self, name):
191+
print "{} is about {}".format(name, self.height)
192+
193+
class Girl(Person):
194+
def __init__(self):
195+
super(Girl, self).__init__()
196+
self.breast = 90
197+
198+
def about(self, name):
199+
print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
200+
super(Girl, self).about(name)
201+
202+
if __name__ == "__main__":
203+
cang = Girl()
204+
cang.about("canglaoshi")
205+
206+
在子类中,`__init__`方法重写了,为了调用父类同方法,使用`super(Girl, self).__init__()`的方式。super函数的参数,第一个是当前子类的类名字,第二个是self,然后是点号,点号后面是所要调用的父类的方法。同样在子类重写的about方法中,也可以调用父类的about方法。
207+
208+
执行结果:
209+
210+
$ python 20903.py
211+
canglaoshi is a hot girl, she is about 160, and her breast is 90
212+
canglaoshi is about 160
213+
214+
最后要提醒注意:super函数仅仅适用于新式类。当然,你一定是使用的新式类。“喜新厌旧”是程序员的嗜好。
215+
216+
------
217+
218+
[总目录](./index.md)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[上节:类(3)](./208.md)&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;[下节:类(5)](./210.md)
219+
220+
如果你认为有必要打赏我,请通过支付宝:**[email protected]**,不胜感激。

2code/20901.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env python
2+
# coding=utf-8
3+
4+
__metaclass__ = type
5+
6+
class Person:
7+
def speak(self):
8+
print "I love you."
9+
10+
def setHeight(self, n):
11+
self.length = n
12+
13+
def breast(self, n):
14+
print "My breast is: ",n
15+
16+
class Girl(Person):
17+
def setHeight(self):
18+
print "The height is:1.70m ."
19+
20+
if __name__ == "__main__":
21+
cang = Girl()
22+
cang.setHeight()
23+
cang.speak()
24+
cang.breast(90)

2code/20902.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env python
2+
# coding=utf-8
3+
4+
__metaclass__ = type
5+
6+
class Person:
7+
8+
def eye(self):
9+
print "two eyes"
10+
11+
def breast(self, n):
12+
print "The breast is: ",n
13+
14+
class Girl:
15+
age = 28
16+
def color(self):
17+
print "The girl is white"
18+
19+
class HotGirl(Person, Girl):
20+
pass
21+
22+
if __name__ == "__main__":
23+
kong = HotGirl()
24+
kong.eye()
25+
kong.breast(90)
26+
kong.color()
27+
print kong.age

2code/20903.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/usr/bin/env python
2+
# coding=utf-8
3+
4+
__metaclass__ = type
5+
6+
class Person:
7+
def __init__(self):
8+
self.height = 160
9+
10+
def about(self, name):
11+
print "{} is about {}".format(name, self.height)
12+
13+
class Girl(Person):
14+
def __init__(self):
15+
super(Girl, self).__init__()
16+
self.breast = 90
17+
18+
def about(self, name):
19+
print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
20+
super(Girl, self).about(name)
21+
22+
if __name__ == "__main__":
23+
cang = Girl()
24+
cang.about("canglaoshi")

index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
6. [类(1)](./206.md)==>类的初步认识和基本概念理解:问题空间、对象、面向对象、类和实例化类
5454
7. [类(2)](./207.md)==>新式类和旧式类,类的命名,构造函数,实例化及方法和属性,self的作用
5555
8. [类(3)](./208.md)==>类属性和实例属性,类内外数据流转,命名空间、作用域
56+
9. [类(4)](./209.md)==>继承,多重继承,super函数
5657

5758
##第三部分:模块
5859

0 commit comments

Comments
 (0)