2.4.1 定义

本节目标:

  • 掌握如何定义类

类的定义

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) # 可以!

大家可能已经发现,函数中也有类似的情况。 这就牵涉到名称空间和作用域的概念了。

Last updated