0%

第九章 类

9.1 创建和使用类

使用类几乎可以模拟任何东西。

9.1.1 创建一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
class Dog:
"""创建一个类来模拟小狗"""
def __init__(self, name, age):
self.name = name
self.age = age

def sit(self):
"""模拟小狗收到命令时蹲下"""
print(f"{self.name} is now sitting.")

def roll_over(self):
"""模拟小狗收到命令时打滚"""
print(f"{self.name} rolled over!")
  • 类中的函数称为方法
  • 通过实例访问的变量称为属性

方法__init__():方法__init__()是一个特殊方法,每当根据类创建一个新实例时,Python都会自动运行它。在这个方法的定义中,形参self必不可少,而且必须位于其他形参的前面。每个与实例相关联的方法调用都会自动传递实参self,它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。

注意:方法__init__() 前后有两个_。

9.1.2 根据类创建实例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Dog:
"""创建一个类来模拟小狗"""
def __init__(self, name, age):
self.name = name
self.age = age

def sit(self):
"""模拟小狗收到命令时蹲下"""
print(f"{self.name} is now sitting.")

def roll_over(self):
"""模拟小狗收到命令时打滚"""
print(f"{self.name} rolled over!")

my_dog = Dog('willie', 6)
print(f"My dog`s name is {my_dog.name}")
print(f"My og is {my_dog.age} years old")

输出结果为:

1
2
My dog`s name is willie
My dog is 6 years old
  1. 访问属性

要访问实例的属性,可使用句点表示法。

1
my_dog.name
  1. 调用方法

要调用方法,可指定实例的名称和要调用的方法,并用句点分隔。

1
2
my_dog.sit()
my_dog.roll_over()

9.2 使用类和实例

可使用类来模拟现实世界中的很多情景。类编写好后,大部分时间将花在根据类创建的实例上。可以直接修改实例的属性,也可以编写方法以特定的方式进行修改。

9.2.1 修改属性的值

  1. 直接修改属性的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class Dog:
    """创建一个类来模拟小狗"""
    def __init__(self, name, age):
    self.name = name
    self.age = age

    def sit(self):
    """模拟小狗收到命令时蹲下"""
    print(f"{self.name} is now sitting.")

    def roll_over(self):
    """模拟小狗收到命令时打滚"""
    print(f"{self.name} rolled over!")

    my_dog = Dog('willie', 6)
    print(f"My dog`s name is {my_dog.name}")
    print(f"My dog is {my_dog.age} years old")
    my_dog.age = 7 #直接修改属性的值
    print(f"Now, My dog is {my_dog.age} years old")

    输出结果为:

    1
    2
    3
    My dog`s name is willie
    My dog is 6 years old
    Now, My dog is 7 years old
  2. 通过方法修改属性的值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    class Dog:
    """创建一个类来模拟小狗"""
    def __init__(self, name, age):
    self.name = name
    self.age = age

    def sit(self):
    """模拟小狗收到命令时蹲下"""
    print(f"{self.name} is now sitting.")

    def roll_over(self):
    """模拟小狗收到命令时打滚"""
    print(f"{self.name} rolled over!")

    def add_age(self, add_value):
    self.age = self.age + add_value

    my_dog = Dog('willie', 6)
    print(f"My dog`s name is {my_dog.name}")
    print(f"My dog is {my_dog.age} years old")
    my_dog.add_age(2)
    print(f"Now, My dog is {my_dog.age} years old")

    输出结果为:

    1
    2
    3
    My dog`s name is willie
    My dog is 6 years old
    Now, My dog is 8 years old

9.3 继承

编写类时,并非总是要从空白开始。如果要编写的类是另一个现成类的特殊版本,可使用继承。一个类继承另一个类时,将自动获得另一个类的所有属性和方法。原有的类称为父类,而新类称为子类。子类继承了父类的所有属性和方法,同时还可以定义自己的属性和方法。

9.3.1 子类的方法__init__()

在既有类的基础上编写新类时,通常要调用父类的方法__init__()。这将初始化在父类__init__()方法中定义的所有属性。从而让子类包含这些属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Dog:
"""创建一个类来模拟小狗"""
def __init__(self, name, age):
self.name = name
self.age = age

def sit(self):
"""模拟小狗收到命令时蹲下"""
print(f"{self.name} is now sitting.")

def roll_over(self):
"""模拟小狗收到命令时打滚"""
print(f"{self.name} rolled over!")

def add_age(self, add_value):
self.age = self.age + add_value

class SeaDog(Dog):
def __init__(self, name, age):
super().__init__(name, age)


my_sea_dog = SeaDog('sea_willie', 10)
print(f"My dog`s name is {my_sea_dog.name}")
print(f"My dog is {my_sea_dog.age} years old")

输出结果为:

1
2
My dog`s name is sea_willie
My dog is 10 years old

super()是一个特殊函数,能够调用父类的方法。父类也称为超类(superclass),名称super由此而来。

9.3.2 给子类定义属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Dog:
"""创建一个类来模拟小狗"""
def __init__(self, name, age):
self.name = name
self.age = age

def sit(self):
"""模拟小狗收到命令时蹲下"""
print(f"{self.name} is now sitting.")

def roll_over(self):
"""模拟小狗收到命令时打滚"""
print(f"{self.name} rolled over!")

def add_age(self, add_value):
self.age = self.age + add_value

class SeaDog(Dog):
def __init__(self, name, age):
super().__init__(name, age)
self.skill = 'swim' #定义子类自己的属性

def describe_sea_dog(self): #定义子类自己的方法
print(f"sea dog can {self.skill}")

my_sea_dog = SeaDog('sea_willie', 10)
print(f"My dog`s name is {my_sea_dog.name}")
print(f"My dog is {my_sea_dog.age} years old")
my_sea_dog.describe_sea_dog()

输出结果为:

1
2
3
My dog`s name is sea_willie
My dog is 10 years old
sea dog can swim

9.3.3 重写父类的方法

对于父类的方法,只要它不符合子类模拟的实物行为,都可以进行重写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Dog:
"""创建一个类来模拟小狗"""
def __init__(self, name, age):
self.name = name
self.age = age

def sit(self):
"""模拟小狗收到命令时蹲下"""
print(f"{self.name} is now sitting.")

def roll_over(self):
"""模拟小狗收到命令时打滚"""
print(f"{self.name} rolled over!")

def add_age(self, add_value):
self.age = self.age + add_value

class SeaDog(Dog):
def __init__(self, name, age):
super().__init__(name, age)
self.skill = 'swim'

def describe_sea_dog(self):
print(f"sea dog can {self.skill}")

def roll_over(self):# 重写父类的打滚方法
print("sea dog can't roll over!")

my_sea_dog = SeaDog('sea_willie', 10)
print(f"My dog`s name is {my_sea_dog.name}")
print(f"My dog is {my_sea_dog.age} years old")
my_sea_dog.describe_sea_dog()
my_sea_dog.roll_over()

输出结果为:

1
2
3
4
My dog`s name is sea_willie
My dog is 10 years old
sea dog can swim
sea dog can't roll over!

9.3.4 将实例用作属性

使用代码模拟实物时,可能会发现自己给类添加的细节越来越多:属性和方法清单以及文件都越来越长。在这种情况下,可能需要将类的一部分提取出来,作为一个单独的类。可以将大型类拆分成多个协同工作得小类。

9.4 导入类

随着不断给类添加功能,文件可能变得很长,即便妥善地使用了继承亦如此。为遵循Python的总体理念,应让文件尽可能整洁。Python在这方面提供了帮助,允许将类存储在模块中,然后在主程序中导入所需的模块。

9.4.1 导入单个类

1
from module_name import ClassName

9.4.2从一个模块中导入多个类

1
from module_name import ClassName1, ClassName2, ClassName3

9.4.3 导入整个模块

1
import module_name

9.4.4 导入模块中的所有类

1
from module_name import *

9.4.5 使用别名

1
from module_name import ClassName as CN

9.5 Python标准库

Python标准库是一组模块,安装的Python都包含它。

模块random演示

在这个模块中,一个有趣的函数是randint()。它将两个整数作为参数,并随机返回一个位于这两个整数之间(含)的整数。

1
2
3
from random import randint
for x in range(6):
print(randint(1, 6))

输出结果为:

1
2
3
4
5
6
4
6
5
2
6
5

另一个有用的函数是choic()。它将一个列表或元组作为参数,并随机返回其中的一个元素:

1
2
3
4
from random import choice
numbers = [1, 2, 3, 4, 5, 6]
for x in range(5):
print(choice(numbers))

输出结果为:

1
2
3
4
5
5
3
4
1
1

9.6 类编码风格

类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例命名和模块命名都采用小写格式,并在单词之间加上下划线。

在类中,可使用一个空行来分隔方法;而在模块中,可使用两个空行来分隔类。

需要同时导入标准库中的模块和编写的模块时,先编写导入标准库模块的语句,再添加一个空行,然后编写导入自己编写的模块语句。在包含多条import语句的程序中,这种做法让人更容易明白程序使用的各个模块都来自何处。