本节目标:
类的定义
Learning By Reading 难度:★ 重要性:★★★★★
继承
[继承](https://zh.wikipedia.org/zh-hans/继承_(计算机科学))是面向对象的一个基本概念,如果一个类別A「继承自」另一个类別B,就把这个A称为「B的子类別」,而把B称为「A的父类別」也可以称「B是A的超类」。 继承可以使得子类別具有父类別的各种属性和方法,而不需要再次编写相同的代码。在令子类別继承父类別的同时,可以重新定义某些属性,并重写某些方法。
比如,“哺乳动物”类继承“动物”类,“人”类又继承“哺乳动物”类。
Learning By Reading 难度:★ 重要性:★★★★★
如果我们定义
class MyTurtle(turtle.Turtle):
_all_turtles = {}
def __init__(self, *args, name="", **kwds): # args和kwds主要用来把除了name之外的参数传给turtle.Turtle的__init__,这样我们还是可以MyTurtle('turtle', name='ada')创建出一个小海龟形状的小海龟
super(MyTurtle).__init__(*args, **kwds) # 很重要!MyTurtle继承了turtle.Turtle,而turtle.Turtle.__init__里面还做了许多其他事情
self.name = name or "Ishmael" # 给小海龟起名字,如果没有指定名字……管我叫以实玛利吧!
if self.name in MyTurtle._all_turtles:
raise Exception("重名了!") # raise语句用来报错,你们曾经看过的各种错误都可以通过raise报出来。
MyTurtle._all_turtles[name] = self
def polygon(self, n, side):
for i in range(n):
self.fd(side)
self.rt(360. / n)
那么这个MyTurtle
就是一个继承了Turtle
的类。 一个Turtle
对象有的属性和方法,MyTurtle
对象都有。 除此之外,MyTurtle
还有一个polygon
方法,画一个边长为side
的正n
边形。
这时候,我们
my_turtle = MyTurtle()
my_turtle.polygon(42)
就画出了一个边长为42
的正方形。
MyTurtle
类有一个类属性_all_turtles
用一个dict
按名字存了所有小海龟。
ada = MyTurtle(name='ada')
print(ada._all_turtles)
这样也打印出了所有小海龟。 Python发现对象ada
没有_all_turtles
这个属性,于是就会去ada
所属的类MyTurtle
去找有没有这个属性。
ada = MyTurtle(name='ada')
ada._all_turtles = 42
print(ada._all_turtles) # 结果:42
print(MyTurtle._all_turtles)
对ada
的属性赋值不会影响类属性。
注意类体与函数体的区别
类体中的代码会在定义的过程中执行,而函数体中的代码不会。
def polygon(turtle, n, side):
print("画一个多边形")
for i in range(n):
turtle.fd(side)
turtle.rt(360. / n)
这段代码定义了一个函数polygon
,但是函数中的print
在定义的过程中没有被执行。
而
class MyTurtle(turtle.Turtle):
print("定义继承了Turtle的MyTurtle类")
def polygon(self, n, side):
for i in range(n):
self.fd(side)
self.rt(360. / n)
这段代码定义了一个类,类体中的print
会被执行。
def _polygon(turtle, n, side):
for i in range(n):
turtle.fd(side)
turtle.rt(360. / n)
class MyTurtle(turtle.Turtle):
polygon = _polygon
这段代码定义了函数_polygon
,类MyTurtle
,类中有方法polygon
。 这时候,
my_turtle = MyTurtle()
my_turtle.polygon(42) # 语句1
MyTurtle.polygon(my_turtle, 42) # 语句2
_polygon(my_turtle, 42) # 语句3
语句1、2、3是等价的。
if MyTurtle.polygon == _polygon:
print("相等!") # 会输出
会输出相等!
。
同样的,
turtle = Turtle()
turtle.fd(42)
Turtle.fd(turtle, 42)
两句话也是等价的。
在类体中定义的变量,都会变成类的属性和方法。
但是,在类体定义的变量,无法在外面使用。
比如,
class MyTurtle(turtle.Turtle):
master = "Your Name" # 类属性,小海龟主人名字
def polygon(self, n, side):
for i in range(n):
self.fd(side)
self.rt(360. / n)
print(master) # 报错!
print(MyTurtle.master) # 可以!
大家可能已经发现,函数中也有类似的情况。 这就牵涉到名称空间和作用域的概念了。