Python面向对象
类
- 创建类和其中的函数
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
26class Person:
# 默认初始化方法
def __init__(self):
self.name = ''
self.age = 0
# 定义打印方法
def display(self):
print("Person({name}, {age})" .format(name = self.name,age = self.age))
# 重写对象生成字符串方法
def __str__(self):
return "Person(%s, %d)" % (self.name, self.age)
# 重写默认表示
def __repr__(self):
return str(self)
# 简化打印方法
def display_simple(self):
print(self)
p = Person()
p.name = 'Bob'
p.age = 30
# p.display()
# p.__str__()
str(p)
# p
# p.display_simple() - 类的初始化
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Person:
# 带参数的初始化方法
def __init__(self, name, age):
self.name = name
self.age = age
# 重写对象生成字符串方法
def __str__(self):
return "Person(%s, %d)" % (self.name, self.age)
# 重写默认表示
def __repr__(self):
return str(self)
# 初始化Person对象
p = Person('Bob', 30)
p - 函数修饰器
- @property:将 方法 转换成 属性,可以使用属性访问语法来调用方法,保持了接口的统一性和简洁性。访问属性格式:obj.属性名
- @属性名.setter:必须在property定义之后声明。设置属性格式:obj.属性名 = 值
- @属性名.deleter:删除属性格式:del obj.属性名
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# 不使用@property修饰器时,获取属性和设置属性写法:
class TemperatureWithoutProperty:
def __init__(self, celsius=0):
self._celsius = celsius
def get_celsius(self):
"""获取摄氏温度"""
print(f"获取摄氏温度: {self._celsius}°C")
return self._celsius
def set_celsius(self, value):
"""设置摄氏温度(带验证)"""
if value < -273.15:
print("错误:温度不能低于绝对零度(-273.15°C)")
raise ValueError("温度不能低于绝对零度")
print(f"设置摄氏温度: {value}°C")
self._celsius = value
temp1 = TemperatureWithoutProperty(25)
print(f"初始温度: {temp1.get_celsius()}°C")
temp1.set_celsius(30)
print(f"新的摄氏温度: {temp1.get_celsius()}°C")
try:
temp1.set_celsius(-300)
except ValueError as e:
print(f"捕获错误: {e}")
# 使用@property修饰器时,获取属性和设置属性写法:
class TemperatureWithProperty:
def __init__(self, celsius=0):
self._celsius = celsius
def celsius(self):
"""摄氏温度属性getter"""
print(f"[getter] 获取摄氏温度: {self._celsius}°C")
return self._celsius
def celsius(self, value):
"""摄氏温度属性setter"""
if value < -273.15:
print(f"[setter] 错误:温度不能低于绝对零度(-273.15°C)")
raise ValueError("温度不能低于绝对零度")
print(f"[setter] 设置摄氏温度: {value}°C")
self._celsius = value
temp2 = TemperatureWithProperty(25)
print(f"初始温度: {temp2.celsius}°C")
temp2.celsius=30
print(f"新的摄氏温度: {temp2.celsius}°C")
try:
temp2.celsius = -300
except ValueError as e:
print(f"捕获错误: {e}")
私有变量:使用单下划线开头的是保护变量/方法,约定俗成认为该变量应避免外部访问;使用双下划线开头的是私有变量/方法,外部不能直接访问或修改
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
30class TemperatureWithProperty:
def __init__(self, celsius=0):
self.__celsius = celsius
def celsius(self):
"""摄氏温度属性getter"""
print(f"[getter] 获取摄氏温度: {self.__celsius}°C")
return self.__celsius
def celsius(self, value):
"""摄氏温度属性setter"""
if value < -273.15:
print(f"[setter] 错误:温度不能低于绝对零度(-273.15°C)")
raise ValueError("温度不能低于绝对零度")
print(f"[setter] 设置摄氏温度: {value}°C")
self.__celsius = value
def __private_method(self):
print('这是私有方法')
p = TemperatureWithProperty(25)
# print(p.__celsius) # 直接访问双下划线的变量会报错
p.__celsius = 5000 # 虽然双下划线开头的变量可以赋值,但是并不影响对象中的保护变量的值
print(p.__celsius)
# 5000
print(p.celsius)
# 25
# p.__private_method() # 调用私有方法会报没有此方法继承:可以单继承,也可以多继承。使用super()调用父类方法。尽量使用组合而不是多继承
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# 单继承
# 定义玩家
class Player():
def __init__(self, name):
self._name = name
self._score = 0
def incr_score(self):
self._score = self._score + 1
def __str__(self):
return "name = %s, score = %d" % (self._name, self._score)
def __repr__(self):
return "Player(%s)" % str(self)
# 人继承玩家
class Human(Player):
pass
h = Human('Jack')
print(h)
h.incr_score()
print(h)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# 多继承
class A:
def method(self):
print("A")
class B(A):
def method(self):
print("B")
super().method()
class C(A):
def method(self):
print("C")
super().method()
# D多继承B和C
class D(B, C):
def method(self):
print("D")
super().method()
print("\n" + "=" * 50)
print("最终测试:预测输出顺序")
print("=" * 50)
d = D()
d.method()
print(D.__mro__) # 获取继承方法解析顺序
print("D的MRO:", [cls.__name__ for cls in D.__mro__])
==================================================
最终测试:预测输出顺序
==================================================
D
B
C
A
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
D的MRO: ['D', 'B', 'C', 'A', 'object']组合:允许一个类包含另一个类的实例作为自己的属性。以汽车继承交通工具为例,组合中汽车有交通工具中的引擎。可以降低耦合度
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# ============================================
# 最简单的组合Demo:电脑由组件组成
# 核心思想:电脑 "有" 组件,而不是电脑 "是" 组件
# ============================================
# 1. 定义组件类
class CPU:
"""CPU组件"""
def __init__(self, brand, cores):
self.brand = brand
self.cores = cores
def process(self):
return f"{self.brand} CPU正在处理,{self.cores}核"
class Memory:
"""内存组件"""
def __init__(self, size):
self.size = size
def load_data(self):
return f"加载数据到 {self.size}GB 内存"
class HardDrive:
"""硬盘组件"""
def __init__(self, capacity):
self.capacity = capacity
def store_data(self):
return f"存储数据到 {self.capacity}GB 硬盘"
# 2. 定义电脑类 - 使用组合
class Computer:
"""电脑类 - 由组件组合而成"""
def __init__(self):
# 组合:电脑有CPU、内存、硬盘
self.cpu = CPU("Intel", 8) # 创建CPU实例
self.memory = Memory(16) # 创建内存实例
self.hard_drive = HardDrive(512) # 创建硬盘实例
def power_on(self):
"""开机"""
print("正在开机...")
print(f"1. {self.cpu.process()}") # 调用CPU组件方法
print(f"2. {self.memory.load_data()}") # 调用内存组件方法
print(f"3. {self.hard_drive.store_data()}") # 调用硬盘组件方法
print("电脑启动完成!")
# 3. 使用电脑
print("=" * 40)
print("组合示例:电脑由组件组成")
print("=" * 40)
# 创建电脑对象
my_computer = Computer()
# 使用电脑功能
my_computer.power_on()
# 可以直接访问和操作组件
print(f"\n电脑组件详情:")
print(f"- CPU: {my_computer.cpu.brand} {my_computer.cpu.cores}核")
print(f"- 内存: {my_computer.memory.size}GB")
print(f"- 硬盘: {my_computer.hard_drive.capacity}GB")
# 也可以单独使用组件
print(f"\n单独使用CPU组件:")
cpu_only = CPU("AMD", 12)
print(cpu_only.process())重写:要求方法名和参数数量(默认参数除外)相同,可以使用super()调用父类方法。(python支持重写,但不支持重载,如果子类中的函数名与父类中的相同,但参数不同,则会覆盖父类中的函数。在一个类中有多个名称相同的函数,则以最后一个函数为准)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20class Payment:
# ✅ 设置参数数据类型
def pay(self, amount: int):
self.amount = amount
print(f"支付%d元" % self.get_money())
# ✅ 指定函数返回数据类型
def get_money(self) -> int:
return self.amount
class CreditCardPayment(Payment):
# ✅ 可以添加默认参数,不影响原有调用
def pay(self, amount, card_type="Visa"):
print(f"使用{card_type}信用卡支付 {amount} 元")
super().pay(amount) # 调用父类方法
# 测试
payment = CreditCardPayment()
payment.pay(100) # ✅ 可以调用,使用默认参数
payment.pay(200, "MasterCard") # ✅ 也可以传入新参数封装
- 使用@property + 私有变量 = 最佳封装实践
- 根据类创建对象
- 获取对象的属性
- 查看类的父类
- 通过对象动态添加类的属性
- 修改属性
- self的用法
- init()初始化
多态
- 不同子类对象调用相同父类方法,产生不同的执行效果,可以增加代码的灵活性
- 前提:继承+重写父类的方法
- 定义
文件操作
- 异常
- 定义
- 有异常不会影响下面代码执行
- 常用Exception类、else、finally
- 模块
- 定义:就是一个.py文件
- 通过import 模块名
- 通过from 模块名 import 方法名/对象名
- 模块别名 form 模块名 import 方法名 as 别名
- 文件读写
- 打开文件
- 读/写
- 关闭文件
打开方式
- r:只读,文件不存在会报异常
- w:只写,覆盖原文件,文件不存在则创建。
- encoding:指定编码格式,win写入需要指定格式,默认格式为cp936->GBK
- 注意:文件被打开之后,多次写入数据不会覆盖之前的数据
- a:追加写入- b:二进制形式
- 注意:二进制模式下不需要添加encoding参数
- rb:二进制方式打开文件用于只读;
- 对二进制的数据斤进行解码操作,将bytes类型转换为str类型
- 将str转换为bytes类型
- rw:二进制方式打开一个文件用于只写
- b:二进制形式
匿名函数
- 定义:函数没有名字,用lambda关键字进行定义
- 创建
常用python包
- PIL:图像处理
- Tkinter: Python GUI
- Django:交互式网站
- Bottle:小型交互式网站
- Pygame:2D动画
- SciPy:科学计算
- Twisted:网络编程
- PyPI:Python索引包
- 标题: Python面向对象
- 作者: Henry
- 创建于 : 2025-12-30 15:44:50
- 更新于 : 2026-01-06 16:53:22
- 链接: https://mybetterworks.github.io/2025/12/30/Python面向对象/
- 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论