# 面向对象基础

学习目标

  • 理解面向对象
  • 类和对象
  • 添加和获取对象属性
  • 魔法方法

理解面向对象

  • 面向对象是一种抽象化的编程思想,很多编程语⾔言中都有的一种思想。
    • 例如:洗衣服
  • 思考:几种途径可以完成洗衣服?
    • 答: 手洗 和 机洗。
      • 手洗:找盆 - 放水 - 加洗衣粉 - 浸泡 - 搓洗 - 拧干水 - 倒水 - 漂洗N次 - 拧干 - 晾晒。
      • 机洗:打开洗衣机 - 放衣服 - 加洗衣粉 - 按下开始按钮 - 晾晒。
  • 思考:对⽐比两种洗衣服途径,同学们发现了什么?
    • 答:机洗更简单
  • 思考:机洗,只需要找到一台洗衣机,加入简单操作就可以完成洗衣服的工作,而不需要关心洗衣机内部发生了什么事情。
  • 总结:面向对象就是将编程当成是一个事物,对外界来说,事物是直接使用的,不用去管他内部的情况。而编程就是设置事物能够做什么事。

类和对象

  • 思考:洗衣机洗衣服描述过程中,洗衣机其实就是一个事物,即对象,洗衣机对象哪来的呢?
    • 答:洗衣机是由工厂工人制作出来。
  • 思考:工厂工人怎么制作出的洗衣机?
    • 答:工人根据设计师设计的功能图纸制作洗衣机。
  • 总结:图纸 → 洗衣机 → 洗衣服。
  • 在面向对象编程过程中,有两个重要组成部分:类 和 对象。
  • 类和对象的关系:用类去创建一个对象。

理解类和对象

  • 类是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真实存在的事物。
    • 特征即是属性
    • 行为即是方法
  • 类⽐比如是制造洗衣机时要用到的图纸,也就是说类是用来创建对象。

对象

  • 对象是类创建出来的真实存在的事物,例如:洗衣机。
  • 注意:开发中,先有类,再有对象。

面向对象实现方法

定义类

  • Python2中类分为:经典类 和 新式类

  • 语法

    • 注意:类名要满足标识符命名规则,同时遵循⼤大驼峰命名习惯。
1
2
3
class 类名():
代码
......
  • 体验
1
2
3
class Washer():
def wash(self):
print('我会洗衣服')
  • 拓展:经典类
    • 不由任意内置类型派生出的类,称之为经典类
1
2
3
class 类名:
代码
......

创建对象

  • 对象又名实例。
  • 语法
1
对象名 = 类名()
  • 体验
    • 注意:创建对象的过程也叫实例化对象
1
2
3
4
5
6
7
8
# 创建对象
haier1 = Washer()

# <__main__.Washer object at 0x0000018B7B224240>
print(haier1)

# haier对象调用实例方法
haier1.wash()

self

  • self指的是调用该函数的对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1. 定义类
class Washer():
def wash(self):
print('我会洗衣服')
# <__main__.Washer object at 0x0000024BA2B34240>
print(self)

# 2. 创建对象
haier1 = Washer()
# <__main__.Washer object at 0x0000018B7B224240>
print(haier1)
# haier1对象调用实例方法
haier1.wash()

haier2 = Washer()
# <__main__.Washer object at 0x0000022005857EF0>
print(haier2)
  • 注意:打印对象和self得到的结果是一致的,都是当前对象的内存中存储地址。

添加和获取对象属性

  • 属性即是特征,⽐比如:洗衣机的宽度、高度、重量…
  • 对象属性既可以在类外面添加和获取,也能在类里面添加和获取。

类外面添加对象属性

  • 语法
1
对象名.属性名 = 值
  • 体验
1
2
haier1.width = 500
haier1.height = 800

类外面获取对象属性

  • 语法
1
对象名.属性名
  • 体验
1
2
print(f'haier1洗衣机的宽度是{haier1.width}')
print(f'haier1洗衣机的高度是{haier1.height}')

类里面获取对象属性

  • 语法
1
self.属性名
  • 体验
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 定义类
class Washer():
def print_info(self):
# 类里面获取实例属性
print(f'haier1洗衣机的宽度是{self.width}')
print(f'haier1洗衣机的高度是{self.height}')

# 创建对象
haier1 = Washer()

# 添加实例属性
haier1.width = 500
haier1.height = 800

haier1.print_info()

魔法方法

  • 在Python中, __xx__() 的函数叫做魔法方法,指的是具有特殊功能的函数。

_ _ init _ _()

体验_ _ init _ _()

  • 思考:洗衣机的宽度高度是与生俱来的属性,可不可以在生产过程中就赋予这些属性呢?

  • 答:理应如此。

  • __init__() 方法的作用:初始化对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Washer():

# 定义初始化功能的函数
def __init__(self):
# 添加实例属性
self.width = 500
self.height = 800

def print_info(self):
# 类里面调用实例属性
print(f'洗衣机的宽度是{self.width}, 高度是{self.height}')

haier1 = Washer()
haier1.print_info()
  • 注意:
  • __init__() 方法,在创建一个对象时默认被调用,不需要手动调用
  • __init__(self) 中的self参数,不需要开发者传递,python解释器器会自动把当前的对象引用传递过去。

带参数的_ _ init _ _()

  • 思考:一个类可以创建多个对象,如何对不同的对象设置不同的初始化属性呢?
  • 答:传参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Washer():
def __init__(self, width, height):
self.width = width
self.height = height

def print_info(self):
print(f'洗衣机的宽度是{self.width}')
print(f'洗衣机的高度是{self.height}')

haier1 = Washer(10, 20)
haier1.print_info()

haier2 = Washer(30, 40)
haier2.print_info()

_ _ str _ _()

  • 当使用print输出对象的时候,默认打印对象的内存地址。如果类定义了__str__ 方法,那么就会打印从在这个方法中 return 的数据。
1
2
3
4
5
6
7
8
9
10
11
class Washer():
def __init__(self, width, height):
self.width = width
self.height = height

def __str__(self):
return '这是海海尔洗衣机的说明书'

haier1 = Washer(10, 20)
# 这是海海尔洗衣机的说明书
print(haier1)

_ _del _ _()

  • 当删除对象时,python解释器器也会默认调用__del__() 方法。
1
2
3
4
5
6
7
8
9
10
11
12
class Washer():
def __init__(self, width, height):
self.width = width
self.height = height

def __del__(self):
print(f'{self}对象已经被删除')

haier1 = Washer(10, 20)

# <__main__.Washer object at 0x0000026118223278>对象已经被删除
del haier1

综合应用

烤地瓜

需求

  • 需求主线:
    • 被烤的时间和对应的地瓜状态:
      • 0-3分钟:生的
      • 3-5分钟:半生不熟
      • 5-8分钟:熟的
      • 超过8分钟:烤糊了
    • 添加的调料:
      • 用户可以按自己的意愿添加调料

步骤分析

  • 需求涉及一个事物: 地瓜,故案例涉及一个类:地瓜类。

  • 定义类

    • 地瓜的属性
      • 被烤的时间
      • 地瓜的状态
      • 添加的调料
    • 地瓜的方法
      • 被烤
        • 用户根据意愿设定每次烤地瓜的时间
        • 判断地瓜被烤的总时间是在哪个区间,修改地瓜状态
      • 添加调料
        • 用户根据意愿设定添加的调料
        • 将用户添加的调料存储
    • 显示对象信息
  • 创建对象,调用相关实例方法

代码实现

  • 定义类
    • 地瓜属性
      • 定义地瓜初始化属性,后期根据程序推进更新实例属性
1
2
3
4
5
6
7
8
class SweetPotato():
def __init__(self):
# 被烤的时间
self.cook_time = 0
# 地瓜的状态
self.cook_static = '生的'
# 调料列表
self.condiments = []

定义烤地瓜方法

1
2
3
4
5
6
7
8
9
10
11
12
13
class SweetPotato():
......
def cook(self, time):
"""烤地瓜的方法"""
self.cook_time += time
if 0 <= self.cook_time < 3:
self.cook_static = '生的'
elif 3 <= self.cook_time < 5:
self.cook_static = '半生不熟'
elif 5 <= self.cook_time < 8:
self.cook_static = '熟了'
elif self.cook_time >= 8:
self.cook_static = '烤糊了'

输出对象状态

1
2
3
4
class SweetPotato():
......
def __str__(self):
return f'这个地瓜烤了{self.cook_time}分钟, 状态是{self.cook_static}'

测试实例属性和实例方法

1
2
3
4
digua1 = SweetPotato()
print(digua1)
digua1.cook(2)
print(digua1)

定义调料方法,并调用该方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class SweetPotato():
......
def add_condiments(self, condiment):
"""添加调料"""
self.condiments.append(condiment)
def __str__(self):
return f'这个地瓜烤了{self.cook_time}分钟, 状态是{self.cook_static}, 添加的调料有{self.condiments}'

digua1 = SweetPotato()
print(digua1)

digua1.cook(2)
digua1.add_condiments('酱油')
print(digua1)

digua1.cook(2)
digua1.add_condiments('辣椒面⼉儿')
print(digua1)

digua1.cook(2)
print(digua1)

digua1.cook(2)
print(digua1)

代码总览

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
34
35
36
37
38
39
40
41
42
43
44
45
# 定义类
class SweetPotato():
def __init__(self):
# 被烤的时间
self.cook_time = 0
# 地瓜的状态
self.cook_static = '生的'
# 调料列表
self.condiments = []

def cook(self, time):
"""烤地瓜的方法"""
self.cook_time += time
if 0 <= self.cook_time < 3:
self.cook_static = '生的'
elif 3 <= self.cook_time < 5:
self.cook_static = '半生不熟'
elif 5 <= self.cook_time < 8:
self.cook_static = '熟了'
elif self.cook_time >= 8:
self.cook_static = '烤糊了'

def add_condiments(self, condiment):
"""添加调料"""
self.condiments.append(condiment)

def __str__(self):
return f'这个地瓜烤了{self.cook_time}分钟, 状态是{self.cook_static}, 添加的调料有{self.condiments}'

digua1 = SweetPotato()
print(digua1)

digua1.cook(2)
digua1.add_condiments('酱油')
print(digua1)

digua1.cook(2)
digua1.add_condiments('辣椒面⼉儿')
print(digua1)

digua1.cook(2)
print(digua1)

digua1.cook(2)
print(digua1)

搬家具

需求

  • 将小于房子剩余面积的家具摆放到房子中

步骤分析

  • 需求涉及两个事物:房子 和 家具,故被案例涉及两个类:房子类 和 家具类。

  • 定义类

    • 房子类
      • 实例属性
        • 房子地理位置
        • 房子占地面积
        • 房子剩余面积
        • 房子内家具列表
      • 实例方法
        • 容纳家具
      • 显示房屋信息
    • 家具类
      • 家具名称
      • 家具占地面积
  • 创建对象并调用相关方法

代码实现

  • 定义家具类
1
2
3
4
5
6
class Furniture():
def __init__(self, name, area):
# 家具名字
self.name = name
# 家具占地面积
self.area = area
  • 房子类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Home():
def __init__(self, address, area):
# 地理位置
self.address = address
# 房屋面积
self.area = area
# 剩余面积
self.free_area = area
# 家具列表
self.furniture = []

def __str__(self):
return f'房子坐落于{self.address}, 占地面积{self.area}, 剩余面积{self.free_area}, 家具有{self.furniture}'

def add_furniture(self, item):
"""容纳家具"""
if self.free_area >= item.area:
self.furniture.append(item.name)
# 家具搬入后,房屋剩余面积 = 之前剩余面积 - 该家具面积
self.free_area -= item.area
else:
print('家具太⼤大,剩余面积不足,无法容纳')

创建对象并调用实例属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
bed = Furniture('双人床', 6)
jia1 = Home('北北京', 1200)
print(jia1)

jia1.add_furniture(bed)
print(jia1)

sofa = Furniture('沙发', 10)
jia1.add_furniture(sofa)
print(jia1)

ball = Furniture('篮球场', 1500)
jia1.add_furniture(ball)
print(jia1)

总结

  • 面向对象重要组成部分
    • 创建类
1
2
class 类名():
代码
  • 对象
1
对象名 = 类名()
  • 添加对象属性
1
2
3
4
5
# 类外面
对象名.属性名 = 值

# 类里面
self.属性名 = 值
  • 获取对象属性
1
2
3
4
5
# 类外面
对象名.属性名

# 类里面
self.属性名
  • 魔法方法

    • __init__() : 初始化

    • __str__() :输出对象信息

    • __del__() :删除对象时调用

继承

学习目标

  • 继承的概念
  • 单继承
  • 多继承
  • 子类重写父类的同名属性和方法
  • 子类调用父类的同名属性和方法
  • 多层继承
  • super()
  • 私有属性和私有方法

继承的概念

  • 生活中的继承,一般指的是子⼥女女继承父辈的财产。

image-20240206200722364

  • 拓展1:经典类或旧式类
    • 不由任意内置类型派生出的类,称之为经典类。
1
2
3
class 类名:
代码
......
  • 拓展2:新式类
1
2
class 类名(object):
代码
  • Python面向对象的继承指的是多个类之间的所属关系,即子类默认继承父类的所有属性和方法,具体如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
# 父类A
class A(object):
def __init__(self):
self.num = 1
def info_print(self):
print(self.num)

# 子类B
class B(A):
pass

result = B()
result.info_print() # 1
  • 在Python中,所有类默认继承object类,object类是顶级类或基类;其他子类叫做派生类。

单继承

  • 故事主线:一个煎饼果子老师傅,在煎饼果子界摸爬滚打多年,研发了一套精湛的摊煎饼果子的技术。师父要把这套技术传授给他的唯一的最得意的徒弟。
  • 分析:徒弟是不是要继承师父的所有技术?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 1. 师父类
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

# 2. 徒弟类
class Prentice(Master):
pass

# 3. 创建对象daqiu
daqiu = Prentice()

# 4. 对象访问实例属性
print(daqiu.kongfu)

# 5. 对象调用实例方法
daqiu.make_cake()

多继承

  • 故事推进:daqiu是个爱学习的好孩子,想学习更多的煎饼果子技术,于是,在百度搜索到⿊黑⻢马程序员,报班学习煎饼果子技术。

  • 所谓多继承意思就是一个类同时继承了多个父类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

# 创建学校类
class School(object):
def __init__(self):
self.kongfu = '[⿊黑⻢马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School, Master):
pass

daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()
  • 注意:当一个类有多个父类的时候,默认使用第一个父类的同名属性和方法。

子类重写父类同名方法和属性

  • 故事:daqiu掌握了师父和培训的技术后,自己潜心钻研出自己的独门配方的一套全新的煎饼果子技术。
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 Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'

def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
def __init__(self):
self.kongfu = '[⿊黑⻢马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

# 独创配方
class Prentice(School, Master):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

daqiu = Prentice()
print(daqiu.kongfu)
daqiu.make_cake()

print(Prentice.__mro__)
  • 子类和父类具有同名属性和方法,默认使用子类的同名属性和方法。

子类调用父类同名方法和属性

  • 故事:很多顾客都希望也能吃到古法和⿊黑⻢马的技术的煎饼果子。
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
34
35
36
37
38
39
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
def __init__(self):
self.kongfu = '[⿊黑⻢马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School, Master):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'

def make_cake(self):
# 如果是先调用了父类的属性和方法,父类属性会覆盖子类属性,故在调用属性前,先调用自己子类的初始化
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')

# 调用父类方法,但是为保证调用到的也是父类的属性,必须在调用方法前调用父类的初始化
def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)

def make_school_cake(self):
School.__init__(self)
School.make_cake(self)

daqiu = Prentice()

daqiu.make_cake()

daqiu.make_master_cake()

daqiu.make_school_cake()

daqiu.make_cake()

多层继承

  • 故事:N年后,daqiu老了,想要把所有技术传承给自己的徒弟。
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
34
35
36
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'

def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
def __init__(self):
self.kongfu = '[⿊黑⻢马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School, Master):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'

def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')

def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)

def make_school_cake(self):
School.__init__(self)
School.make_cake(self)

# 徒孙类
class Tusun(Prentice):
pass
xiaoqiu = Tusun()
xiaoqiu.make_cake()
xiaoqiu.make_school_cake()
xiaoqiu.make_master_cake()

super()调用父类方法

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'

def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class School(Master):
def __init__(self):
self.kongfu = '[⿊黑⻢马煎饼果子配方]'

def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')
# 方法2.1
# super(School, self).__init__()
# super(School, self).make_cake()
# 方法2.2
super().__init__()
super().make_cake()

class Prentice(School):
def __init__(self):
self.kongfu = '[独创煎饼果子技术]'

def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')

# 子类调用父类的同名方法和属性:把父类的同名属性和方法再次封装
def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)

def make_school_cake(self):
School.__init__(self)
School.make_cake(self)

# 一次性调用父类的同名属性和方法
def make_old_cake(self):
# 方法一:代码冗余;父类类名如果变化,这里代码需要频繁修改
# Master.__init__(self)
# Master.make_cake(self)
# School.__init__(self)
# School.make_cake(self)
# 方法二: super()
# 方法2.1 super(当前类名, self).函数()
# super(Prentice, self).__init__()
# super(Prentice, self).make_cake()
# 方法2.2 super().函数()
super().__init__()
super().make_cake()

daqiu = Prentice()
daqiu.make_old_cake()
  • 注意:使用super() 可以自动查找父类。调用顺序遵循 mro 类属性的顺序。⽐比较适合单继承使用。

私有权限

定义私有属性和方法

  • 在Python中,可以为实例属性和方法设置私有权限,即设置某个实例属性或实例方法不继承给子类。

  • 故事:daqiu把技术传承给徒弟的同时,不想把自己的钱(2000000个亿)继承给徒弟,这个时候就要为钱这个实例属性设置私有权限。

  • 设置私有权限的方法:在属性名和方法名 前面 加上两个下划线 __

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'

def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
def __init__(self):
self.kongfu = '[⿊黑⻢马煎饼果子配方]'
def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School, Master):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'
# 定义私有属性
self.__money = 2000000

# 定义私有方法
def __info_print(self):
print(self.kongfu)
print(self.__money)

def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')

def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)

def make_school_cake(self):
School.__init__(self)
School.make_cake(self)

# 徒孙类
class Tusun(Prentice):
pass
daqiu = Prentice()
# 对象不能访问私有属性和私有方法
# print(daqiu.__money)
# daqiu.__info_print()

xiaoqiu = Tusun()
# 子类无法继承父类的私有属性和私有方法
# print(xiaoqiu.__money) # 无法访问实例属性__money
# xiaoqiu.__info_print()
  • 注意:私有属性和私有方法只能在类里面访问和修改。

获取和修改私有属性值

  • 在Python中,一般定义函数名get_xx 用来获取私有属性,定义 set_xx 用来修改私有属性值。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Master(object):
def __init__(self):
self.kongfu = '[古法煎饼果子配方]'

def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class School(object):
def __init__(self):
self.kongfu = '[⿊黑⻢马煎饼果子配方]'

def make_cake(self):
print(f'运用{self.kongfu}制作煎饼果子')

class Prentice(School, Master):
def __init__(self):
self.kongfu = '[独创煎饼果子配方]'
self.__money = 2000000

# 获取私有属性
def get_money(self):
return self.__money

# 修改私有属性
def set_money(self):
self.__money = 500

def __info_print(self):
print(self.kongfu)
print(self.__money)

def make_cake(self):
self.__init__()
print(f'运用{self.kongfu}制作煎饼果子')

def make_master_cake(self):
Master.__init__(self)
Master.make_cake(self)

def make_school_cake(self):
School.__init__(self)
School.make_cake(self)

# 徒孙类
class Tusun(Prentice):
pass

daqiu = Prentice()

xiaoqiu = Tusun()
# 调用get_money函数获取私有属性money的值
print(xiaoqiu.get_money())
# 调用set_money函数修改私有属性money的值
xiaoqiu.set_money()
print(xiaoqiu.get_money())

总结

  • 继承的特点
    • 子类默认拥有父类的所有属性和方法
    • 子类重写父类同名方法和属性
    • 子类调用父类同名方法和属性
  • super()方法快速调用父类方法
  • 私有权限
    • 不能继承给子类的属性和方法需要添加私有权限
    • 语法
1
2
3
4
5
6
7
class 类名():
# 私有属性
__属性名 = 值

# 私有方法
def __函数名(self):
代码

三大特性与方法

学习目标

  • 面向对象三⼤大特性
  • 类属性和实例属性
  • 类方法和静态方法

面向对象三⼤大特性

  • 封装
    • 将属性和方法书写到类的里面的操作即为封装
    • 封装可以为属性和方法添加私有权限
  • 继承
    • 子类默认继承父类的所有属性和方法
    • 子类可以重写父类属性和方法
  • 多态
    • 传入不同的对象,产生不同的结果

多态

了解多态

  • 多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)。
    • 定义:多态是一种使用对象的方式,子类重写父类方法,调用不同子类对象的相同父类方法,可以产生不同的执行结果
    • 好处:调用灵活,有了多态,更容易易编写出通用的代码,做出通用的编程,以适应需求的不断变化!
    • 实现步骤:
      • 定义父类,并提供公共方法
      • 定义子类,并重写父类方法
      • 传递子类对象给调用者,可以看到不同子类执行效果不同

体验多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Dog(object):
def work(self): # 父类提供统一的方法,哪怕是空方法
print('指哪打哪...')

class ArmyDog(Dog): # 继承Dog类
def work(self): # 子类重写父类同名方法
print('追击敌人...')

class DrugDog(Dog):
def work(self):
print('追查毒品...')

class Person(object):
def work_with_dog(self, dog): # 传入不同的对象,执行不同的代码,即不同的work函数
dog.work()

ad = ArmyDog()
dd = DrugDog()

daqiu = Person()
daqiu.work_with_dog(ad)
daqiu.work_with_dog(dd)

类属性和实例属性

类属性

设置和访问类属性

  • 类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。
  • 类属性可以使用 类对象 或 实例对象 访问。
1
2
3
4
5
6
7
8
9
class Dog(object):
tooth = 10

wangcai = Dog()
xiaohei = Dog()

print(Dog.tooth) # 10
print(wangcai.tooth) # 10
print(xiaohei.tooth) # 10
  • 类属性的优点
    • 记录的某项数据 始终保持一致时,则定义类属性。
    • 实例属性 要求 每个对象 为其 单独开辟一份内存空间 来记录数据,而 类属性 为全类所共有,仅占用一份内存,更加节省内存空间。

修改类属性

  • 类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了一个实例属性。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Dog(object):
tooth = 10

wangcai = Dog()
xiaohei = Dog()

# 修改类属性
Dog.tooth = 12
print(Dog.tooth) # 12
print(wangcai.tooth) # 12
print(xiaohei.tooth) # 12

# 不能通过对象修改属性,如果这样操作,实则是创建了一个实例属性
wangcai.tooth = 20
print(Dog.tooth) # 12
print(wangcai.tooth) # 20
print(xiaohei.tooth) # 12

实例属性

1
2
3
4
5
6
7
8
9
10
11
class Dog(object):
def __init__(self):
self.age = 5

def info_print(self):
print(self.age)

wangcai = Dog()
print(wangcai.age) # 5
# print(Dog.age) # 报错:实例属性不能通过类访问
wangcai.info_print() # 5

类方法和静态方法

类方法

类方法特点

  • 需要用装饰器器 @classmethod 来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以 cls 作为第一个参数。

类方法使用场景

  • 当方法中 需要使用类对象 (如访问私有类属性等)时,定义类方法
  • 类方法一般和类属性配合使用
1
2
3
4
5
6
7
8
9
10
class Dog(object):
__tooth = 10

@classmethod
def get_tooth(cls):
return cls.__tooth

wangcai = Dog()
result = wangcai.get_tooth()
print(result) # 10

静态方法

静态方法特点

  • 需要通过装饰器器 @staticmethod 来进行修饰,静态方法既不需要传递类对象也不需要传递实例对象(形参没有self/cls)。
  • 静态方法 也能够通过 实例对象 和 类对象 去访问。

静态方法使用场景

  • 当方法中 既不需要使用实例对象(如实例对象,实例属性),也不需要使用类对象 (如类属性、类方法、创建实例等)时,定义静态方法
  • 取消不需要的参数传递,有利利于 减少不必要的内存占用和性能消耗
1
2
3
4
5
6
7
8
9
class Dog(object):
@staticmethod
def info_print():
print('这是一个狗类,用于创建狗实例....')

wangcai = Dog()
# 静态方法既可以使用对象访问又可以使用类访问
wangcai.info_print()
Dog.info_print()

总结

  • 面向对象三⼤大特性
    • 封装
    • 继承
    • 多态
  • 类属性
    • 归属于类对象的属性,所有对象共有的属性
  • 实例属性
  • 类方法
1
2
3
@classmethod
def xx():
代码
  • 静态方法
1
2
3
@staticmethod
def xx():
代码

异常

学习目标

  • 了解异常
  • 捕获异常
  • 异常的else
  • 异常finally
  • 异常的传递
  • 自定义异常

了解异常

  • 当检测到一个错误时,解释器器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的”异常”。
  • 例如:以 r 方式打开一个不存在的文件。
1
open('test.txt', 'r')

image-20240206204222160

异常的写法

语法

1
2
3
4
try:
可能发生错误的代码
except:
如果出现异常执行的代码

快速体验

  • 需求:尝试以 r 模式打开文件,如果文件不存在,则以 w 方式打开。
1
2
3
4
try:
f = open('test.txt', 'r')
except:
f = open('test.txt', 'w')

捕获指定异常

语法

1
2
3
4
try:
可能发生错误的代码
except 异常类型:
如果捕获到该异常类型执行的代码

体验

1
2
3
4
try:
print(num)
except NameError:
print('有错误')
  • 注意:
    • 如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。

    • 一般try下方只放一行尝试执行的代码。

捕获多个指定异常

  • 当捕获多个异常时,可以把要捕获的异常类型的名字,放到except 后,并使用元组的方式进行书写。
1
2
3
4
5
try:
print(1/0)

except (NameError, ZeroDivisionError):
print('有错误')

捕获异常描述信息

1
2
3
4
try:
print(num)
except (NameError, ZeroDivisionError) as result:
print(result)

捕获所有异常

  • Exception是所有程序异常类的父类。
1
2
3
4
try:
print(num)
except Exception as result:
print(result)

异常的else

  • else表示的是如果没有异常要执行的代码。
1
2
3
4
5
6
try:
print(1)
except Exception as result:
print(result)
else:
print('我是else,是没有异常的时候执行的代码')

异常的finally

  • finally表示的是无论是否异常都要执行的代码,例如关闭文件。
1
2
3
4
5
6
7
8
try:
f = open('test.txt', 'r')
except Exception as result:
f = open('test.txt', 'w')
else:
print('没有异常,真开心')
finally:
f.close()

异常的传递

  • 体验异常传递

  • 需求:

    • 尝试只读方式打开test.txt文件,如果文件存在则读取文件内容,文件不存在则提示用户即可。

    • 读取内容要求:尝试循环读取内容,读取过程中如果检测到用户意外终⽌止程序,则except 捕获异常并提示用户。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import time
try:
f = open('test.txt')
try:
while True:
content = f.readline()
if len(content) == 0:
break
time.sleep(2)
print(content)
except:
# 如果在读取文件的过程中,产生了异常,那么就会捕获到
# ⽐比如 按下了 ctrl+c
print('意外终⽌止了读取数据')
finally:
f.close()
print('关闭文件')
except:
print("没有这个文件")

自定义异常

  • 在Python中,抛出自定义异常的语法为raise 异常类对象。
  • 需求:密码长度不足,则报异常(用户输入密码,如果输入的长度不足3位,则报错,即抛出自定义异常,并捕获该异常)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 自定义异常类,继承Exception
class ShortInputError(Exception):
def __init__(self, length, min_len):
self.length = length
self.min_len = min_len

# 设置抛出异常的描述信息
def __str__(self):
return f'你输入的长度是{self.length}, 不能少于{self.min_len}个字符'

def main():
try:
con = input('请输入密码:')
if len(con) < 3:
raise ShortInputError(len(con), 3)
except Exception as result:
print(result)
else:
print('密码已经输入完成')

main()

总结

异常语法

1
2
3
4
5
6
7
8
try:
可能发生异常的代码
except:
如果出现异常执行的代码
else:
没有异常执行的代码
finally:
无论是否异常都要执行的代码

捕获异常

1
2
3
4
5
except 异常类型:
代码

except 异常类型 as xx:
代码

自定义异常

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 自定义异常类
class 异常类类名(Exception):
代码

# 设置抛出异常的描述信息
def __str__(self):
return ...

# 2. 抛出异常
raise 异常类名()

# 捕获异常
except Exception...

模块和包

学习目标

  • 了解模块
  • 导入模块
  • 制作模块
  • __all__
  • 包的使用方法

模块

  • Python 模块(Module),是一个 Python 文件,以 .py 结尾,包含了 Python 对象定义和Python语句。
  • 模块能定义函数,类和变量,模块里也能包含可执行的代码。

导入模块

导入模块的方式

  • import 模块名
  • from 模块名 import 功能名
  • from 模块名 import *
  • import 模块名 as 别名
  • from 模块名 import 功能名 as 别名

导入方式详解

import

  • 语法
1
2
3
4
5
6
# 1. 导入模块
import 模块名
import 模块名1, 模块名2...

# 2. 调用功能
模块名.功能名()
  • 体验
1
2
import math
print(math.sqrt(9)) # 3.0

from..import..

  • 语法
1
from 模块名 import 功能1, 功能2, 功能3...
  • 体验
1
2
from math import sqrt
print(sqrt(9))

from .. import *

  • 语法:
1
from 模块名 import *
  • 体验
1
2
from math import *
print(sqrt(9))

as定义别名

  • 语法
1
2
3
4
5
# 模块定义别名
import 模块名 as 别名

# 功能定义别名
from 模块名 import 功能 as 别名
  • 体验
1
2
3
4
5
6
7
8
9
10
# 模块别名
import time as tt

tt.sleep(2)
print('hello')

# 功能别名
from time import sleep as sl
sl(2)
print('hello')

制作模块

  • 在Python中,每个Python文件都可以作为一个模块,模块的名字就是文件的名字。也就是说自定义模块名必须要符合标识符命名规则。

定义模块

  • 新建一个Python文件,命名为 my_module1.py ,并定义 testA 函数。
1
2
def testA(a, b):
print(a + b)

测试模块

  • 在实际开中,当一个开发人员编写完一个模块后,为了让模块能够在项目中达到想要的效果,这个开发人员会自行在py文件中添加一些测试信息.,例如,在my_module1.py 文件中添加测试代码。
1
2
3
4
def testA(a, b):
print(a + b)

testA(1, 1)
  • 此时,无论是当前文件,还是其他已经导入了该模块的文件,在运行的时候都会自动执行testA 函数的调用。
  • 解决办法如下:
1
2
3
4
5
6
def testA(a, b):
print(a + b)

# 只在当前文件中调用该函数,其他导入的文件内不符合该条件,则不执行testA函数调用
if __name__ == '__main__':
testA(1, 1)

调用模块

1
2
import my_module1
my_module1.testA(1, 1)

注意事项

  • 如果使用 from .. import .. from .. import * 导入多个模块的时候,且模块内有同名功能。当调用这个同名功能的时候,调用到的是后面导入的模块的功能。

  • 体验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 模块1代码
def my_test(a, b):
print(a + b)

# 模块2代码
def my_test(a, b):
print(a - b)

# 导入模块和调用功能代码
from my_module1 import my_test
from my_module2 import my_test

# my_test函数是模块2中的函数
my_test(1, 1)

模块定位顺序

  • 当导入一个模块,Python解析器器对模块位置的搜索顺序是:

    • 当前目录

    • 如果不在当前目录,Python则搜索在shell变量PYTHONPATH下的每个目录。

    • 如果都找不到,Python会察看默认路径。UNIX下,默认路径一般为/usr/local/lib/python/

  • 模块搜索路径存储在system模块的sys.path变量中。变量里包含当前目录,PYTHONPATH和由安装过程决定的默认目录。

    • 注意
    • 自己的文件名不要和已有模块名重复,否则导致模块功能无法使用
    • 使用 from 模块名 import 功能的时候,如果功能名字重复,调用到的是最后定义或导入的功能。

_ _ all _ _

  • 如果一个模块文件中有__all__ 变量,当使用 from xxx import * 导入时,只能导入这个列表中的元素。
  • my_module1模块代码
1
2
3
4
5
6
7
__all__ = ['testA']

def testA():
print('testA')

def testB():
print('testB')
  • 导入模块的文件代码
1
2
3
from my_module1 import *
testA()
testB()

image-20240206210252790

  • 包将有联系的模块组织在一起,即放到同一个文件夹下,并且在这个文件夹创建一个名字为__init__.py 文件,那么这个文件夹就称之为包。

制作包

  • [New] — [Python Package] — 输入包名 — [OK] — 新建功能模块(有联系的模块)。
  • 注意:新建包后,包内部会自动创建__init__.py 文件,这个文件控制着包的导入行为。

快速体验

  1. 新建包mypackage
  2. 新建包内模块: my_module1 和 my_module2
  3. 模块内代码如下
1
2
3
4
5
# my_module1
print(1)

def info_print1():
print('my_module1')
1
2
3
4
5
# my_module2
print(2)

def info_print2():
print('my_module2')

导入包

方法一

1
2
import 包名.模块名
包名.模块名.目标
  • 体验
1
2
import my_package.my_module1
my_package.my_module1.info_print1()

方法二

  • 注意:必须在__init__.py 文件中添加__all__ = [] ,控制允许导入的模块列表。
1
2
from 包名 import *
模块名.目标
  • 体验
1
2
from my_package import *
my_module1.info_print1()

总结

  • 导入模块方法
1
2
3
import 模块名
from 模块名 import 目标
from 模块名 import *
  • 导入包
1
2
import 包名.模块名
from 包名 import *
  • __all__ = [] :允许导入的模块或功能列表

面向对象版学员管理系统

学习目标

  • 了解面向对象开发过程中类内部功能的分析方法
  • 了解常用系统功能
    • 添加
    • 删除
    • 修改
    • 查询

系统需求

  • 使用面向对象编程思想完成学员管理系统的开发,具体如下:
    • 系统要求:学员数据存储在文件中
    • 系统功能:添加学员、删除学员、修改学员信息、查询学员信息、显示所有学员信息、保存学员信息及退出系统等功能。

准备程序文件

分析

  • ⻆角⾊色分析
    • 学员
    • 管理系统
  • 工作中注意事项
    • 为了方便便维护代码,一般一个⻆角⾊色一个程序文件;
    • 项目要有主程序入口,习惯为main.py

创建程序文件

  • 创建项目目录,例如: StudentManagerSystem

  • 程序文件如下:

    • 程序入口文件:main.py
    • 学员文件:student.py
    • 管理系统文件:managerSystem.py

书写程序

student.py

  • 需求:

    • 学员信息包含:姓名、性别、手机号;
    • 添加__str__ 魔法方法,方便便查看学员对象信息
  • 程序代码

1
2
3
4
5
6
7
8
class Student(object):
def __init__(self, name, gender, tel):
self.name = name
self.gender = gender
self.tel = tel

def __str__(self):
return f'{self.name}, {self.gender}, {self.tel}'

managerSystem.py

  • 需求:

    • 存储数据的位置:文件(student.data)
      • 加载文件数据
      • 修改数据后保存到文件
    • 存储数据的形式:列表存储学员对象
    • 系统功能
      • 添加学员
      • 删除学员
      • 修改学员
      • 查询学员信息
      • 显示所有学员信息
      • 保存学员信息
      • 退出系统
  • 定义类:

1
2
3
4
class StudentManager(object):
def __init__(self):
# 存储数据所用的列表
self.student_list = []
  • 管理系统框架
    • 需求:系统功能循环使用,用户输入不同的功能序号执行不同的功能。
    • 步骤
      • 定义程序入口函数
        • 加载数据
        • 显示功能菜单
        • 用户输入功能序号
        • 根据用户输入的功能序号执行不同的功能
      • 定义系统功能函数,添加、删除学员等
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class StudentManager(object):
def __init__(self):
# 存储数据所用的列表
self.student_list = []

# 一. 程序入口函数,启动程序后执行的函数
def run(self):
# 1. 加载学员信息
self.load_student()

while True:
# 2. 显示功能菜单
self.show_menu()

# 3. 用户输入功能序号
menu_num = int(input('请输入您需要的功能序号:'))

# 4 根据用户输入的功能序号执行不同的功能
if menu_num == 1:
# 添加学员
self.add_student()
elif menu_num == 2:
# 删除学员
self.del_student()
elif menu_num == 3:
# 修改学员信息
self.modify_student()
elif menu_num == 4:
# 查询学员信息
self.search_student()
elif menu_num == 5:
# 显示所有学员信息
self.show_student()
elif menu_num == 6:
# 保存学员信息
self.save_student()
elif menu_num == 7:
# 退出系统
break

# 二. 定义功能函数
# 2.1 显示功能菜单
@staticmethod
def show_menu():
print('请选择如下功能-----------------')
print('1:添加学员')
print('2:删除学员')
print('3:修改学员信息')
print('4:查询学员信息')
print('5:显示所有学员信息')
print('6:保存学员信息')
print('7:退出系统')

# 2.2 添加学员
def add_student(self):
pass

# 2.3 删除学员
def del_student(self):
pass

# 2.4 修改学员信息
def modify_student(self):
pass

# 2.5 查询学员信息
def search_student(self):
pass

# 2.6 显示所有学员信息
def show_student(self):
pass

# 2.7 保存学员信息
def save_student(self):
pass

# 2.8 加载学员信息
def load_student(self):
pass

main.py

1
2
3
4
5
6
7
8
# 1. 导入managerSystem模块
from managerSystem import *

# 2. 启动学员管理系统
if __name__ == '__main__':
student_manager = StudentManager()

student_manager.run()

定义系统功能函数

添加功能

  • 需求:用户输入学员姓名、性别、手机号,将学员添加到系统。
  • 步骤
    • 用户输入姓名、性别、手机号
    • 创建该学员对象
    • 将该学员对象添加到列表
  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 添加学员函数内部需要创建学员对象,故先导入student模块
from student import *

class StudentManager(object):
......
# 2.2 添加学员
def add_student(self):
# 1. 用户输入姓名、性别、手机号
name = input('请输入您的姓名:')
gender = input('请输入您的性别:')
tel = input('请输入您的手机号:')

# 2. 创建学员对象:先导入学员模块,再创建对象
student = Student(name, gender, tel)

# 3. 将该学员对象添加到列表
self.student_list.append(student)

# 打印信息
print(self.student_list)
print(student)

删除学员

  • 需求:用户输入目标学员姓名,如果学员存在则删除该学员。
  • 步骤
    • 用户输入目标学员姓名
    • 遍历学员数据列表,如果用户输入的学员姓名存在则删除,否则提示该学员不存在。
  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 2.3 删除学员:删除指定姓名的学员
def del_student(self):
# 1. 用户输入目标学员姓名
del_name = input('请输入要删除的学员姓名:')

# 2. 如果用户输入的目标学员存在则删除,否则提示学员不存在
for i in self.student_list:
if i.name == del_name:
self.student_list.remove(i)
break
else:
print('查无此人!')

# 打印学员列表,验证删除功能
print(self.student_list)

修改学员信息

  • 需求:用户输入目标学员姓名,如果学员存在则修改该学员信息。
  • 步骤
    • 用户输入目标学员姓名;
    • 遍历学员数据列表,如果用户输入的学员姓名存在则修改学员的姓名、性别、手机号数据,否则提示该学员不存在。
  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 2.4 修改学员信息
def modify_student(self):
# 1. 用户输入目标学员姓名
modify_name = input('请输入要修改的学员的姓名:')
# 2. 如果用户输入的目标学员存在则修改姓名、性别、手机号等数据,否则提示学员不存在
for i in self.student_list:
if i.name == modify_name:
i.name = input('请输入学员姓名:')
i.gender = input('请输入学员性别:')
i.tel = input('请输入学员手机号:')
print(f'修改该学员信息成功,姓名{i.name},性别{i.gender}, 手机号{i.tel}')
break
else:
print('查无此人!')

查询学员信息

  • 需求:用户输入目标学员姓名,如果学员存在则打印该学员信息
  • 步骤
    • 用户输入目标学员姓名
    • 遍历学员数据列表,如果用户输入的学员姓名存在则打印学员信息,否则提示该学员不存在。
  • 代码
1
2
3
4
5
6
7
8
9
10
11
# 2.5 查询学员信息
def search_student(self):
# 1. 用户输入目标学员姓名
search_name = input('请输入要查询的学员的姓名:')
# 2. 如果用户输入的目标学员存在,则打印学员信息,否则提示学员不存在
for i in self.student_list:
if i.name == search_name:
print(f'姓名{i.name},性别{i.gender}, 手机号{i.tel}')
break
else:
print('查无此人!')

显示所有学员信息

  • 打印所有学员信息
  • 步骤
    • 遍历学员数据列表,打印所有学员信息
  • 代码
1
2
3
4
5
# 2.6 显示所有学员信息
def show_student(self):
print('姓名\t性别\t手机号')
for i in self.student_list:
print(f'{i.name}\t{i.gender}\t{i.tel}')

保存学员信息

  • 需求:将修改后的学员数据保存到存储数据的文件。
  • 步骤
    • 打开文件
    • 文件写入数据
    • 关闭文件
  • 思考
    • 文件写入的数据是学员对象的内存地址吗?
    • 文件内数据要求的数据类型是什么?
  • 拓展__dict__
1
2
3
4
5
6
7
8
9
10
11
class A(object):
a = 0

def __init__(self):
self.b = 1

aa = A()
# 返回类内部所有属性和方法对应的字典
print(A.__dict__)
# 返回实例属性和值组成的字典
print(aa.__dict__)
  • 在Python中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 2.7 保存学员信息
def save_student(self):
# 1. 打开文件
f = open('student.data', 'w')

# 2. 文件写入学员数据
# 注意1:文件写入的数据不能是学员对象的内存地址,需要把学员数据转换成列表字典数据再做存储
new_list = [i.__dict__ for i in self.student_list]
# [{'name': 'aa', 'gender': 'nv', 'tel': '111'}]
print(new_list)
# 注意2:文件内数据要求为字符串类型,故需要先转换数据类型为字符串才能文件写入数据
f.write(str(new_list))

# 3. 关闭文件
f.close()

加载学员信息

  • 需求:每次进入系统后,修改的数据是文件里面的数据
  • 步骤
    • 尝试以”r” 模式打开学员数据文件,如果文件不存在则以”w” 模式打开文件
    • 如果文件存在则读取数据并存储数据
      • 读取数据
      • 转换数据类型为列表并转换列表内的字典为对象
      • 存储学员数据到学员列表
    • 关闭文件
  • 代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 2.8 加载学员信息
def load_student(self):
# 尝试以"r"模式打开数据文件,文件不存在则提示用户;文件存在(没有异常)则读取数据
try:
f = open('student.data', 'r')
except:
f = open('student.data', 'w')
else:
# 1. 读取数据
data = f.read()

# 2. 文件中读取的数据都是字符串且字符串内部为字典数据,故需要转换数据类型再转换字典为对象后存储到学员列表
new_list = eval(data)
self.student_list = [Student(i['name'], i['gender'], i['tel']) for i in new_list]
finally:
# 3. 关闭文件
f.close()

总结

  • 函数
    • 定义和调用
    • 参数的使用
  • 面向对象
    • 定义类
    • 创建对象
    • 定义和调用实例属性
    • 定义和调用实例方法
  • 数据类型
    • 列表
      • 增加删除数据
      • 列表推导式
    • 字典
    • 字符串
  • 文件操作
    • 打开文件
    • 读取或写入
    • 关闭文件