Repository navigation
Expand file tree
/
Copy path2_3_oop.py
More file actions
231 lines (182 loc) · 7.78 KB
/
Copy path2_3_oop.py
File metadata and controls
231 lines (182 loc) · 7.78 KB
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
================================================================
第二阶段:代码工程化与核心进阶
2.3 面向对象编程(OOP)
================================================================
【课程属性】L1 · 必修 · 预计 120~160 分钟
【前置要求】完成 2.2 异常处理、调试与日志
【学习目标】
1. 理解类与实例的概念
2. 掌握 __init__ 构造函数和属性
3. 掌握实例方法,并能区分类属性与实例属性
4. 理解封装、组合、继承与多态的使用边界
5. 了解常用魔法方法,并能定义简单的业务类
【本课 Python 知识点】
- class / __init__ / self - 类属性 / 实例属性
- 继承 super() - 多态
- 魔法方法 __str__/__repr__ 等 - 私有属性 _ / __
【参考链接】
官方教程(类): https://docs.python.org/zh-cn/3/tutorial/classes.html
Python 数据模型: https://docs.python.org/zh-cn/3/reference/datamodel.html
"""
# ============================================================
# 第一部分:类与实例
# ============================================================
class Dog:
"""狗类"""
species = "Canis familiaris" # 类属性:所有实例共享
def __init__(self, name, age):
self.name = name # 实例属性:每个实例独有
self.age = age
def bark(self): # 实例方法:第一个参数通常按约定命名为 self
return f"{self.name} 汪汪叫"
# 创建实例
my_dog = Dog("旺财", 3)
print(my_dog.name) # 旺财
print(my_dog.bark()) # 旺财 汪汪叫
print(my_dog.species) # Canis familiaris(从类拿到)
print(Dog.species) # 类属性也可以直接用类访问
# 思考:类和实例是什么关系?
# 类 = 图纸(模板),实例 = 按图纸造出来的对象。
# 实例的属性是"自己的",类属性是所有实例共享的。
# ============================================================
# 第二部分:实例方法与类属性
# ============================================================
class Counter:
"""计数器"""
count = 0 # 类属性
def __init__(self, owner):
self.owner = owner
self.value = 0
# 实例方法:操作实例属性
def increment(self):
self.value += 1
Counter.count += 1
return self.value
c1 = Counter("第一个")
c2 = Counter("第二个")
c1.increment()
c1.increment()
c2.increment()
print(c1.value) # 2
print(c2.value) # 1
print(Counter.count) # 3(两个实例共享的类计数)
# 实例方法通过 self 读写某个对象的数据,是最常用的方法。
# 类属性由所有实例共享,应通过类名 Counter.count 明确访问。
# 类方法、静态方法和属性装饰器会在 2.4 学完装饰器原理后再介绍。
# ============================================================
# 第三部分:封装与属性访问
# ============================================================
class BankAccount:
def __init__(self, owner, balance):
self.owner = owner
self._balance = balance # 约定:单下划线=内部使用(约定)
self.__secret = "秘密" # 双下划线会触发名称改写,并非绝对私有
def deposit(self, amount):
if amount > 0:
self._balance += amount
return self._balance
raise ValueError("金额必须为正")
def get_balance(self):
"""对外暴露只读接口"""
return self._balance
account = BankAccount("张三", 1000)
account.deposit(500)
print(account.get_balance()) # 1500
# 双下划线私有属性的原理(面试考点):
# account.__secret → AttributeError
# account._BankAccount__secret → 名称改写后仍然能访问(约定>强制)
# 结论:单下划线表示“内部实现,请勿直接依赖”;双下划线主要防止子类意外重名。
# 它们都不是安全机制,敏感数据不能靠属性命名保护。
# 组合:一个对象把另一个对象作为属性,表达“拥有”关系。
class Engine:
def start(self):
return "发动机启动"
class Car:
def __init__(self, brand, engine):
self.brand = brand
self.engine = engine
def start(self):
return f"{self.brand}:{self.engine.start()}"
print(Car("示例汽车", Engine()).start())
# “汽车拥有发动机”更适合组合;“猫是一种动物”更适合继承。
# ============================================================
# 第四部分:继承与多态
# ============================================================
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("子类必须实现")
class Cat(Animal): # 继承
def speak(self): # 方法重写(override)
return f"{self.name} 喵喵叫"
class Dog(Animal):
def speak(self):
return f"{self.name} 汪汪叫"
# 多态:同一个接口,不同的实现
animals = [Cat("咪咪"), Dog("旺财")]
for animal in animals:
print(animal.speak())
# 咪咪 喵喵叫
# 旺财 汪汪叫
# super():调用父类方法
class Puppy(Dog):
def __init__(self, name, age):
super().__init__(name) # 调用父类的 __init__
self.age = age
self.is_puppy = True
def speak(self):
return super().speak() + "(奶声奶气)"
print(Puppy("小旺", 1).speak()) # 小旺 汪汪叫(奶声奶气)
# 多继承会增加方法查找与状态管理难度,本阶段不要求使用。
# 判断类型:
print(isinstance(Puppy("x", 1), Dog)) # True(Puppy 是 Dog 的子类实例)
print(isinstance("str", str)) # True
# ============================================================
# 第五部分:魔法方法
# ============================================================
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
self._pages = 0
# __str__:print(obj) 时调用,面向用户的可读描述
def __str__(self):
return f"《{self.title}》作者:{self.author}"
# __repr__:repr(obj) 或调试时调用,面向开发者的精确描述
def __repr__(self):
return f"Book(title={self.title!r}, author={self.author!r})"
# __len__:len(obj) 时调用
def __len__(self):
return self._pages
# __call__:让实例可以像函数一样调用
def __call__(self, page):
self._pages += page
return self._pages
book = Book("三体", "刘慈欣")
print(book) # 《三体》作者:刘慈欣(__str__)
print(repr(book)) # Book(title='三体', author='刘慈欣')(__repr__)
book(100) # 调用 __call__,pages=100
book(50) # pages=150
print(len(book)) # 150(__len__)
# 其他常见魔法方法(了解):
# __eq__/__lt__: 比较运算
# __getitem__: obj[key]
# __iter__: 让对象可迭代
# __del__: 析构(一般不自己写)
# ============================================================
# 本课小结
# ============================================================
#
# [ ] 能区分类属性与实例属性
# [ ] 知道 _ 和 __ 的区别
# [ ] 能写继承并解释多态
# [ ] 知道 __str__ 和 __repr__ 的区别
# [ ] 能说明组合与继承分别表达什么关系
# [ ] 能用类完成一个带状态与行为的小程序
# ============================================================
# 课后练习(见 exercises/2_3_oop.py)
# ============================================================