# 2.4.1 定义

本节目标：

* 掌握如何定义类

## 类的定义

**Learning By Reading 难度：★ 重要性：★★★★★**

* 阅读[材料](https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431864715651c99511036d884cf1b399e65ae0d27f7e000)

  ，了解定义类和类中的属性、方法的语法。

## 继承

> \[继承]\(<https://zh.wikipedia.org/zh-hans/继承_(计算机科学))是面向对象的一个基本概念，如果一个类別A「继承自」另一个类別B，就把这个A称为「B的子类別」，而把B称为「A的父类別」也可以称「B是A的超类」。> 继承可以使得子类別具有父类別的各种属性和方法，而不需要再次编写相同的代码。在令子类別继承父类別的同时，可以重新定义某些属性，并重写某些方法。

比如，“哺乳动物”类继承“动物”类，“人”类又继承“哺乳动物”类。

**Learning By Reading 难度：★ 重要性：★★★★★**

* 阅读材料，了解Python中的[继承](https://www.cnblogs.com/jason-lv/p/8325324.html)，

  以及[方法解析顺序](https://www.cnblogs.com/whatisfantasy/p/6046991.html)。

如果我们定义

```python
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`边形。

这时候，我们

```python
my_turtle = MyTurtle()
my_turtle.polygon(42)
```

就画出了一个边长为`42`的正方形。

`MyTurtle`类有一个类属性`_all_turtles`用一个`dict`按名字存了所有小海龟。

```python
ada = MyTurtle(name='ada')
print(ada._all_turtles)
```

这样也打印出了所有小海龟。 Python发现对象`ada`没有`_all_turtles`这个属性，于是就会去`ada`所属的类`MyTurtle`去找有没有这个属性。

```python
ada = MyTurtle(name='ada')
ada._all_turtles = 42
print(ada._all_turtles) # 结果：42
print(MyTurtle._all_turtles)
```

对`ada`的属性赋值不会影响类属性。

## 注意类体与函数体的区别

类体中的代码会在定义的过程中执行，而函数体中的代码不会。

```python
def polygon(turtle, n, side):
    print("画一个多边形")
    for i in range(n):
        turtle.fd(side)
        turtle.rt(360. / n)
```

这段代码定义了一个函数`polygon`，但是函数中的`print`在定义的过程中没有被执行。

而

```python
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`会被执行。

```python
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`。 这时候，

```python
my_turtle = MyTurtle()

my_turtle.polygon(42) # 语句1
MyTurtle.polygon(my_turtle, 42) # 语句2
_polygon(my_turtle, 42) # 语句3
```

语句1、2、3是等价的。

```python
if MyTurtle.polygon == _polygon:
    print("相等！") # 会输出
```

会输出`相等！`。

同样的，

```python
turtle = Turtle()

turtle.fd(42)
Turtle.fd(turtle, 42)
```

两句话也是等价的。

在类体中定义的变量，都会变成类的属性和方法。

但是，在类体定义的变量，无法在外面使用。

比如，

```python
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) # 可以！
```

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://coding-girls-club.gitbook.io/python-turtle-tutorial/2-python-bian-cheng/2.4-ding-yi-lei-mi-gong/2.4.1-ding-yi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
