@@ -164,7 +164,7 @@ Python 3中也有异常:
164164
165165还有一种可能存在,就是重写之后,如果要在子类中继承父类中相应部分,怎么办?
166166
167- ##super函数
167+ ##调用覆盖的方法
168168
169169承接前面的问题和程序,可以对子类` Gril ` 做出这样的修改。
170170
@@ -176,9 +176,9 @@ Python 3中也有异常:
176176 def get_name(self):
177177 return self.name
178178
179- 请读者注意观察` Girl ` 的初始化方法,与前面的有所不同。为了能够继续继承父类的初始化方法,以类方法的方式将父类的初始化函数再次调用 ` Person.__init__(self, name) ` ,同时 ,在子类的` __init__() ` 的参数中,要增加相应的参数` name ` 。这样就回答了前面的问题。
179+ 请读者注意观察` Girl ` 的初始化方法,与前面的有所不同。为了能够使用父类的初始化方法,以类方法的方式调用 ` Person.__init__(self, name) ` 。另外 ,在子类的` __init__() ` 的参数中,要增加相应的参数` name ` 。这样就回答了前面的问题。
180180
181- 在实例化子类的时候,就以下面的方式进行 :
181+ 实例化子类,以下面的方式运行程序 :
182182
183183 if __ name__ == "__ main__ ":
184184 cang = Girl("canglaoshi")
@@ -194,108 +194,40 @@ Python 3中也有异常:
194194 {'height': 160}
195195 {'breast': 90}
196196
197- 对于初始化函数的继承,跟一般方法的继承,还有点不同。可以看下面的例子:
197+ 就这样,使用类方法的方式,将父类中被覆盖的方法再次在子类中实现。
198198
199- #!/usr/bin/env python
200- # coding=utf-8
201-
202- __metaclass__ = type
203-
204- class Person:
205- def __init__(self):
206- self.height = 160
207-
208- def about(self, name):
209- print "{} is about {}".format(name, self.height)
210-
211- class Girl(Person):
212- def __init__(self):
213- self.breast = 90
214-
215- def about(self, name):
216- print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
217-
218- if __name__ == "__main__":
219- cang = Girl()
220- cang.about("canglaoshi")
221-
222- 在上面这段程序中,类Girl继承了类Person。在类Girl中,初始化设置了` self.breast = 90 ` ,由于继承了Person,按照前面的经验,Person的初始化函数中的` self.height = 160 ` 也应该被Girl所继承过来。然后在重写的about方法中,就是用` self.height ` 。
223-
224- 实例化类Girl,并执行` cang.about("canglaoshi") ` ,试图打印出一句话` canglaoshi is a hot girl, she is about 160, and her bereast is 90 ` 。保存程序,运行之:
225-
226- $ python 20903.py
227- Traceback (most recent call last):
228- File "20903.py", line 22, in <module>
229- cang.about("canglaoshi")
230- File "20903.py", line 18, in about
231- print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
232- AttributeError: 'Girl' object has no attribute 'height'
233-
234- 报错!
235-
236- 程序员有一句名言:不求最好,但求报错。报错不是坏事,是我们长经验的时候,是在告诉我们,那么做不对。
237-
238- 重要的是看报错信息。就是我们要打印的那句话出问题了,报错信息显示` self.height ` 是不存在的。也就是说类Girl没有从Person中继承过来这个属性。
239-
240- 原因是什么?仔细观察类Girl,会发现,除了刚才强调的about方法重写了,` __init__ ` 方法,也被重写了。不要认为它的名字模样奇怪,就不把它看做类中的方法(函数),它跟类Person中的` __init__ ` 重名了,也同样是重写了那个初始化函数。
241-
242- 这就提出了一个问题。因为在子类中重写了某个方法之后,父类中同样的方法被遮盖了。那么如何再把父类的该方法调出来使用呢?纵然被遮盖了,应该还是存在的,不要浪费了呀。
243-
244- python中有这样一种方法,这种方式是被提倡的方法:super函数。
245-
246- #!/usr/bin/env python
247- # coding=utf-8
248-
249- __metaclass__ = type
250-
251- class Person:
252- def __init__(self):
253- self.height = 160
254-
255- def about(self, name):
256- print "{} is about {}".format(name, self.height)
199+ 但上述方式有一个问题,如果父类的名称因为某种目前你无法预料的原因修改了,子类中该父类的的名称也要修改,有如果程序比较复杂或者忘记了,就会出现异常。于是乎,就有了更巧妙的方法——` super ` 。再重写子类。
257200
258201 class Girl(Person):
259- def __init__(self):
260- super(Girl, self).__init__()
261- self.breast = 90
262-
263- def about(self, name):
264- print "{} is a hot girl, she is about {}, and her breast is {}".format(name, self.height, self.breast)
265- super(Girl, self).about(name)
266-
267- if __name__ == "__main__":
268- cang = Girl()
269- cang.about("canglaoshi")
270-
271- 在子类中,` __init__ ` 方法重写了,为了调用父类同方法,使用` super(Girl, self).__init__() ` 的方式。super函数的参数,第一个是当前子类的类名字,第二个是self,然后是点号,点号后面是所要调用的父类的方法。同样在子类重写的about方法中,也可以调用父类的about方法。
202+ def __init__(self, name):
203+ #Person.__init__(self, name)
204+ super(Girl, self).__init__(name)
205+ self.real_name = "Aoi sola"
272206
273- 执行结果:
207+ def get_name(self):
208+ return self.name
274209
275- $ python 20903.py
276- canglaoshi is a hot girl, she is about 160, and her breast is 90
277- canglaoshi is about 160
210+ 仅仅修改一处,将` Person.__init__(self, name) ` 去掉,修改为` super(Girl, self).__init__(name) ` 。实行程序后,显示的结果与以前一样。
278211
279- 最后要提醒注意:super函数仅仅适用于新式类。当然,你一定是使用的新式类。“喜新厌旧”是程序员的嗜好 。
212+ 关于 ` super ` ,有人做了非常深入的研究,推荐读者阅读 [ 《Python’s super() considered super! 》 ] ( https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ ) ,文中已经探究了 ` super ` 的工作过程。读者如果要深入了解,可以阅读这篇文章 。
280213
214+ ###多重继承
281215
282- ##多重继承
216+ 前面所说的继承,父类都只有一个。但,继承可以来自多个“父”,这就是多重继承。
283217
284- 所谓多重继承,就是指某一个类的父类 ,不止一个,而是多个。比如:
218+ 所谓多重继承,就是指某一个子类的父类 ,不止一个,而是多个。比如:
285219
286220 #!/usr/bin/env python
287221 # coding=utf-8
288222
289- __metaclass__ = type
290-
291- class Person:
223+ class Person(object): #Python 3: class Person:
292224 def eye(self):
293- print "two eyes"
225+ print "two eyes" #Python 3: print("two eyes"),下同,从略
294226
295227 def breast(self, n):
296228 print "The breast is: ",n
297229
298- class Girl:
230+ class Girl(object): #Python 3: class Gril :
299231 age = 28
300232 def color(self):
301233 print "The girl is white"
@@ -310,32 +242,32 @@ python中有这样一种方法,这种方式是被提倡的方法:super函数
310242 kong.color()
311243 print kong.age
312244
313- 在这个程序中,前面有两个类:Person和Girl,然后第三个类HotGirl继承了这两个类 ,注意观察继承方法,就是在类的名字后面的括号中把所继承的两个类的名字写上。但是第三个类中什么方法也没有。
245+ 在这个程序中,前面有两个类` Person ` 和 ` Girl ` ,然后第三个类 ` HotGirl ` 继承了这两个类 ,注意观察继承方法,就是在类的名字后面的括号中把所继承的两个类的名字写上。但是第三个类中什么方法也没有。
314246
315- 然后实例化类HotGirl ,既然继承了上面的两个类,那么那两个类的方法就都能够拿过来使用。保存程序,运行一下看看
247+ 然后实例化类 ` HotGirl ` ,既然继承了上面的两个类,那么那两个类的方法就都能够拿过来使用。保存程序,运行一下看看
316248
317249 $ python 20902.py
318250 two eyes
319251 The breast is: 90
320252 The girl is white
321253 28
322254
323- 值得注意的是,这次在类Girl中 ,有一个` age = 28 ` ,在对HotGirl实例化之后,因为继承的原因,这个类属性也被继承到HotGirl中 ,因此通过实例属性` kong.age ` 一样能够得到该数据。
255+ 值得注意的是,这次在类 ` Girl ` 中 ,有一个` age = 28 ` ,在对HotGirl实例化之后,因为继承的原因,这个类属性也被继承到 ` HotGirl ` 中 ,因此通过实例属性` kong.age ` 一样能够得到该数据。
324256
325257由上述两个实例,已经清楚看到了继承的特点,即将父类的方法和属性全部承接到子类中;如果子类重写了父类的方法,就使用子类的该方法,父类的被遮盖。
326258
327- ##多重继承的顺序
259+ 多重继承的顺序很必要了解。
328260
329- 多重继承的顺序很必要了解。 比如,如果一个子类继承了两个父类,并且两个父类有同样的方法或者属性,那么在实例化子类后,调用那个方法或属性,是属于哪个父类的呢?造一个没有实际意义,纯粹为了解决这个问题的程序:
261+ 比如,如果一个子类继承了两个父类,并且两个父类有同样的方法或者属性,那么在实例化子类后,调用那个方法或属性,是属于哪个父类的呢?造一个没有实际意义,纯粹为了解决这个问题的程序:
330262
331263 #!/usr/bin/env python
332264 # coding=utf-8
333265
334- class K1(object):
266+ class K1(object): #Python 3: class K1:
335267 def foo(self):
336- print "K1-foo"
268+ print "K1-foo" #Python 3: print("K1-foo"),下同,从略
337269
338- class K2(object):
270+ class K2(object): #Python 3: class K2:
339271 def foo(self):
340272 print "K2-foo"
341273 def bar(self):
@@ -364,14 +296,16 @@ python中有这样一种方法,这种方式是被提倡的方法:super函数
364296 K1-foo
365297 J2-bar
366298
367- 代码中的` print C.__mro__ ` 是要打印出类的继承顺序。从上面清晰看出来了。如果要执行foo() 方法,首先看J1 ,没有,看J2 ,还没有,看J1里面的K1 ,有了,即C==>J1==>J2==>K1;bar()也是按照这个顺序,在J2中就找到了一个 。
299+ 代码中的` print C.__mro__ ` 是要打印出类的继承顺序。从上面清晰看出来了。如果要执行 ` foo() ` 方法,首先看 ` J1 ` ,没有,看 ` J2 ` ,还没有,看 ` J1 ` 里面的 ` K1 ` ,有了,即C==>J1==>J2==>K1;` bar() ` 也是按照这个顺序,在 ` J2 ` 中就找到了一个 。
368300
369301这种对继承属性和方法搜索的顺序称之为“广度优先”。
370302
371- 新式类用以及python3.x中都是按照此顺序原则搜寻属性和方法的 。
303+ Python 2的新式类,以及Python 3中都是按照此顺序原则搜寻属性和方法的 。
372304
373305但是,在旧式类中,是按照“深度优先”的顺序的。因为后面读者也基本不用旧式类,所以不举例。如果读者愿意,可以自己模仿上面代码,探索旧式类的“深度优先”含义。
374306
307+ 导致新式类和Python 3中继承顺序较旧式类有所变化,其原因是mro(Method Resolution Order)算法,读者对此若有兴趣,可以到网上搜索关于这个算法的内容进行了解。
308+
375309
376310------
377311
0 commit comments