@@ -164,7 +164,7 @@ Python 3中也有异常:
164
164
165
165
还有一种可能存在,就是重写之后,如果要在子类中继承父类中相应部分,怎么办?
166
166
167
- ##super函数
167
+ ##调用覆盖的方法
168
168
169
169
承接前面的问题和程序,可以对子类` Gril ` 做出这样的修改。
170
170
@@ -176,9 +176,9 @@ Python 3中也有异常:
176
176
def get_name(self):
177
177
return self.name
178
178
179
- 请读者注意观察` Girl ` 的初始化方法,与前面的有所不同。为了能够继续继承父类的初始化方法,以类方法的方式将父类的初始化函数再次调用 ` Person.__init__(self, name) ` ,同时 ,在子类的` __init__() ` 的参数中,要增加相应的参数` name ` 。这样就回答了前面的问题。
179
+ 请读者注意观察` Girl ` 的初始化方法,与前面的有所不同。为了能够使用父类的初始化方法,以类方法的方式调用 ` Person.__init__(self, name) ` 。另外 ,在子类的` __init__() ` 的参数中,要增加相应的参数` name ` 。这样就回答了前面的问题。
180
180
181
- 在实例化子类的时候,就以下面的方式进行 :
181
+ 实例化子类,以下面的方式运行程序 :
182
182
183
183
if __ name__ == "__ main__ ":
184
184
cang = Girl("canglaoshi")
@@ -194,108 +194,40 @@ Python 3中也有异常:
194
194
{'height': 160}
195
195
{'breast': 90}
196
196
197
- 对于初始化函数的继承,跟一般方法的继承,还有点不同。可以看下面的例子:
197
+ 就这样,使用类方法的方式,将父类中被覆盖的方法再次在子类中实现。
198
198
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 ` 。再重写子类。
257
200
258
201
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"
272
206
273
- 执行结果:
207
+ def get_name(self):
208
+ return self.name
274
209
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) ` 。实行程序后,显示的结果与以前一样。
278
211
279
- 最后要提醒注意:super函数仅仅适用于新式类。当然,你一定是使用的新式类。“喜新厌旧”是程序员的嗜好 。
212
+ 关于 ` super ` ,有人做了非常深入的研究,推荐读者阅读 [ 《Python’s super() considered super! 》 ] ( https://rhettinger.wordpress.com/2011/05/26/super-considered-super/ ) ,文中已经探究了 ` super ` 的工作过程。读者如果要深入了解,可以阅读这篇文章 。
280
213
214
+ ###多重继承
281
215
282
- ##多重继承
216
+ 前面所说的继承,父类都只有一个。但,继承可以来自多个“父”,这就是多重继承。
283
217
284
- 所谓多重继承,就是指某一个类的父类 ,不止一个,而是多个。比如:
218
+ 所谓多重继承,就是指某一个子类的父类 ,不止一个,而是多个。比如:
285
219
286
220
#!/usr/bin/env python
287
221
# coding=utf-8
288
222
289
- __metaclass__ = type
290
-
291
- class Person:
223
+ class Person(object): #Python 3: class Person:
292
224
def eye(self):
293
- print "two eyes"
225
+ print "two eyes" #Python 3: print("two eyes"),下同,从略
294
226
295
227
def breast(self, n):
296
228
print "The breast is: ",n
297
229
298
- class Girl:
230
+ class Girl(object): #Python 3: class Gril :
299
231
age = 28
300
232
def color(self):
301
233
print "The girl is white"
@@ -310,32 +242,32 @@ python中有这样一种方法,这种方式是被提倡的方法:super函数
310
242
kong.color()
311
243
print kong.age
312
244
313
- 在这个程序中,前面有两个类:Person和Girl,然后第三个类HotGirl继承了这两个类 ,注意观察继承方法,就是在类的名字后面的括号中把所继承的两个类的名字写上。但是第三个类中什么方法也没有。
245
+ 在这个程序中,前面有两个类` Person ` 和 ` Girl ` ,然后第三个类 ` HotGirl ` 继承了这两个类 ,注意观察继承方法,就是在类的名字后面的括号中把所继承的两个类的名字写上。但是第三个类中什么方法也没有。
314
246
315
- 然后实例化类HotGirl ,既然继承了上面的两个类,那么那两个类的方法就都能够拿过来使用。保存程序,运行一下看看
247
+ 然后实例化类 ` HotGirl ` ,既然继承了上面的两个类,那么那两个类的方法就都能够拿过来使用。保存程序,运行一下看看
316
248
317
249
$ python 20902.py
318
250
two eyes
319
251
The breast is: 90
320
252
The girl is white
321
253
28
322
254
323
- 值得注意的是,这次在类Girl中 ,有一个` age = 28 ` ,在对HotGirl实例化之后,因为继承的原因,这个类属性也被继承到HotGirl中 ,因此通过实例属性` kong.age ` 一样能够得到该数据。
255
+ 值得注意的是,这次在类 ` Girl ` 中 ,有一个` age = 28 ` ,在对HotGirl实例化之后,因为继承的原因,这个类属性也被继承到 ` HotGirl ` 中 ,因此通过实例属性` kong.age ` 一样能够得到该数据。
324
256
325
257
由上述两个实例,已经清楚看到了继承的特点,即将父类的方法和属性全部承接到子类中;如果子类重写了父类的方法,就使用子类的该方法,父类的被遮盖。
326
258
327
- ##多重继承的顺序
259
+ 多重继承的顺序很必要了解。
328
260
329
- 多重继承的顺序很必要了解。 比如,如果一个子类继承了两个父类,并且两个父类有同样的方法或者属性,那么在实例化子类后,调用那个方法或属性,是属于哪个父类的呢?造一个没有实际意义,纯粹为了解决这个问题的程序:
261
+ 比如,如果一个子类继承了两个父类,并且两个父类有同样的方法或者属性,那么在实例化子类后,调用那个方法或属性,是属于哪个父类的呢?造一个没有实际意义,纯粹为了解决这个问题的程序:
330
262
331
263
#!/usr/bin/env python
332
264
# coding=utf-8
333
265
334
- class K1(object):
266
+ class K1(object): #Python 3: class K1:
335
267
def foo(self):
336
- print "K1-foo"
268
+ print "K1-foo" #Python 3: print("K1-foo"),下同,从略
337
269
338
- class K2(object):
270
+ class K2(object): #Python 3: class K2:
339
271
def foo(self):
340
272
print "K2-foo"
341
273
def bar(self):
@@ -364,14 +296,16 @@ python中有这样一种方法,这种方式是被提倡的方法:super函数
364
296
K1-foo
365
297
J2-bar
366
298
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 ` 中就找到了一个 。
368
300
369
301
这种对继承属性和方法搜索的顺序称之为“广度优先”。
370
302
371
- 新式类用以及python3.x中都是按照此顺序原则搜寻属性和方法的 。
303
+ Python 2的新式类,以及Python 3中都是按照此顺序原则搜寻属性和方法的 。
372
304
373
305
但是,在旧式类中,是按照“深度优先”的顺序的。因为后面读者也基本不用旧式类,所以不举例。如果读者愿意,可以自己模仿上面代码,探索旧式类的“深度优先”含义。
374
306
307
+ 导致新式类和Python 3中继承顺序较旧式类有所变化,其原因是mro(Method Resolution Order)算法,读者对此若有兴趣,可以到网上搜索关于这个算法的内容进行了解。
308
+
375
309
376
310
------
377
311
0 commit comments