封装
习题1.1
创建一个 Person 类,包含 name 和 age 两个实例属性。
○ 将 age 属性设置为“私有”(使用双下划线 __age
)。
○ 使用 @property
装饰器为 __age
提供一个 getter 方法,确保年龄获取时总是返回正整数。
○ 为 __age
提供一个 setter 方法,确保设置的年龄是介于 0 到 120 之间的整数。如果不在范围内,则打印警告并拒绝设置,或将其设置为有效默认值。
○ 创建 Person 对象并测试 age 属性的读写。
参考:
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/6 21:12
class Person:
def __init__(self, name, age):
# 直接调用setter方法,以便在初始化时也能应用验证逻辑
self.__age = age
self.name = name
@property
def age(self):
return max(0, self.__age)
@age.setter
def age(self, value):
if not isinstance(value, int):
print(f"警告,年龄必须是整数,拒绝设置:{value}")
elif not (0 <= value <= 120):
print(f"警告,年龄必须介于0到120之间,拒绝设置:{value}")
else:
self.__age = value
def display_info(self):
print(f"姓名:{self.name}, 年龄:{self.age}")
p1 = Person("Adele", 30)
p1.display_info()
print(f"Adele的年龄是:{p1.age}")
p1.age = 32
p1.display_info()
p1.age = 130
p1.display_info()
p1.age = 25.5
p1.display_info()
习题1.2
创建一个 TemperatureConverter
类,用于华氏度和摄氏度之间的转换。
○ 内部存储一个“私有”属性 __celsius
(摄氏度)。
○ 使用 @property
装饰器,提供 celsius 属性的 getter 和 setter。
○ 提供一个 fahrenheit 属性的 getter 和 setter,当设置华氏度时,自动计算并更新内部的 __celsius
值;当获取华氏度时,自动从 __celsius
计算并返回。
■ 摄氏度转华氏度:F=Ctimes1.8+32
■ 华氏度转摄氏度:C=(F−32)/1.8
○ 创建对象并测试双向转换。
参考答案
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/7 22:51
class TemperatureConverter:
def __init__(self, celsius = 0):
self.__celsius = celsius
@property
def celsius(self):
print("获取摄氏度...")
return self.__celsius
@celsius.setter
def celsius(self, value):
if not isinstance(value, (int, float)):
raise ValueError(f"警告:温度必须是数字,{value}是非法的!")
print(f"设置摄氏度是:{value}")
self.__celsius = value
@property
def fahrenheit(self):
"""
根据内部存储的摄氏度计算并返回华氏度
`F=Ctimes1.8+32`
"""
print("获取华氏度...")
return self.__celsius * 1.8 + 32
@fahrenheit.setter
def fahrenheit(self, value):
"""
设置华氏度,并自动计算更新内部的 __celsius 值
`C=(F−32)/1.8`
"""
if not isinstance(value, (int, float)):
raise ValueError(f"警告:温度必须是数字,{value}是非法的!")
print(f"设置华氏度为: {value}℉")
self.__celsius = (value - 32) / 1.8
# 初始化为25摄氏度
converter1 = TemperatureConverter(celsius=25)
print(f"对应的摄氏度:{converter1.celsius}")
print(f"对应的华氏度:{converter1.fahrenheit}")
# 设置华氏度为68
converter1.fahrenheit = 68
print(f"对应的摄氏度:{converter1.celsius}")
print(f"对应的华氏度:{converter1.fahrenheit}")
继承
习题2.1
创建一个 Vehicle 父类,包含 make (品牌) 和 model (型号) 属性,以及一个 start_engine()
方法。
○ 创建一个 Car 子类,继承自 Vehicle。
○ 在 Car 类的 __init__
方法中调用父类的 __init__
方法,并添加一个 num_doors
(车门数量) 属性。
○ 为 Car 类添加一个 honk() 方法。
○ 创建 Car 对象并测试所有方法。
参考答案:
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 13:22
class Vehicle:
"""
包含 make (品牌) 和 model (型号) 属性,以及一个 `start_engine() `方法
"""
def __init__(self, make, model):
self.make = make
self.model = model
print(f"Vehicle {self.make}-{self.model} 实例被创建")
def start_engine(self):
print(f"Vehicle {self.make}-{self.model} start_engine方法被调用... ")
class Car(Vehicle):
def __init__(self, make, model, num_doors = 4):
super().__init__(make, model)
self.num_doors = num_doors
print(f"实例车 {self.make}-{self.model}被创建,车门数量是:{self.num_doors}")
def honk(self):
print(f"实例车 {self.make}-{self.model} honk方法被调用")
c = Car("A", "B", 4)
c.start_engine()
c.honk()
习题2.2
创建一个 Logger 类,包含一个 log(message) 方法。
○ 创建一个 Notifier 类,包含一个 notify(message) 方法。
○ 创建一个 SystemMonitor 类,多重继承 Logger 和 Notifier。
○ 在 SystemMonitor 的 __init__
方法中,使用 super().__init__()
(注意多重继承中 super() 的用法)确保所有父类的初始化逻辑被调用(如果它们有 __init__
)。
○ 在 SystemMonitor 中添加一个 check_status()
方法,该方法调用 log() 和 notify()。
○ 创建 SystemMonitor 对象并测试 check_status()
。
注意下面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
30
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 13:30
class Logger:
def __init__(self):
print("Logger构造函数被调用...")
def log(self, message):
print(f"Logger的消息:{message}")
class Notifier:
def __init__(self):
print("Notifier构造函数被调用...")
def notify(self, message):
print(f"Notifier的消息:{message}")
class SystemMonitor(Logger, Notifier):
def __init__(self):
super().__init__()
print("SystemMonitor构造函数被调用...")
def check_status(self, message):
self.log(message)
self.notify(message)
sys_monitor = SystemMonitor()
sys_monitor.check_status("设备运行良好")
print(SystemMonitor.__mro__)
可以看到虽然SystemMonitor同时继承自Logger和Notifier,但是调用构造函数只调用了Logger,而没有调用Notifier。为了让所有父类的 __init__
方法都被调用,需要确保 继承链上的所有类都使用 super().__init__()
来调用它们的下一个父类。
写法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
30
31
32
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 13:30
class Logger:
def __init__(self):
super().__init__()
print("Logger构造函数被调用...")
def log(self, message):
print(f"Logger的消息:{message}")
class Notifier:
def __init__(self):
super().__init__()
print("Notifier构造函数被调用...")
def notify(self, message):
print(f"Notifier的消息:{message}")
class SystemMonitor(Logger, Notifier):
def __init__(self):
super().__init__()
print("SystemMonitor构造函数被调用...")
def check_status(self, message):
self.log(message)
self.notify(message)
sys_monitor = SystemMonitor()
sys_monitor.check_status("设备运行良好")
print(SystemMonitor.__mro__)
方法重写
习题3.1
创建一个 Shape 父类,包含一个 area() 方法,该方法打印“This is a generic shape.”。
○ 创建一个 Rectangle 子类,继承自 Shape。
○ 在 Rectangle 的 __init__
方法中接收 width 和 height。
○ 重写 Rectangle 的 area() 方法,计算并返回矩形的面积。
○ 创建一个 Circle 子类,继承自 Shape。
○ 在 Circle 的 __init__
方法中接收 radius。
○ 重写 Circle 的 area() 方法,计算并返回圆的面积(使用 PI = 3.14159
)。
○ 创建 Shape、Rectangle 和 Circle 对象,并分别调用它们的 area() 方法。
参考:
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 14:11
PI = 3.14159
class Shape:
def area(self):
print("This is a generic shape.")
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return PI * self.radius
s = Shape()
s.area()
r = Rectangle(5, 8)
area_r = r.area()
print(f"Rectangle,长-{r.width}, 高-{r.height}, 面积是:{area_r}")
c = Circle(3)
area_c = c.area()
print(f"圆的半径是:{c.radius}, 面积是:{area_c}")
习题3.2
创建一个 Employee 父类,包含 name 和 salary 属性,以及一个 calculate_bonus()
方法,该方法返回 salary * 0.10
。
○ 创建一个 Manager 子类,继承自 Employee。
○ 重写 Manager 的 calculate_bonus()
方法,使其返回 salary * 0.15
。
○ 创建 Employee 和 Manager 对象,并测试它们的奖金计算。
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 14:20
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
print(f"员工-{self.name}被创建, 薪资是{self.salary}")
def calculate_bonus(self):
bonus = self.salary * 0.1
print(f"基础奖金是:{bonus}")
return bonus
class Manager(Employee):
def __init__(self, name, saraly):
super().__init__(name, saraly)
def calculate_bonus(self):
bonus = self.salary * 0.15
print(f"基础奖金是:{bonus}")
return bonus
e = Employee("Adele", 6000)
bonus_e = e.calculate_bonus()
print(f"员工:{e.name}的奖金是:{bonus_e}")
e2 = Manager("Bob", 6000)
bonus_e2 = e2.calculate_bonus()
print(f"员工:{e2.name}的奖金是:{bonus_e2}")
Object
习题4.1
创建一个 Vector2D 类,表示二维向量,包含 x 和 y 两个属性。
○ 重写 __str__
方法,使其打印出 “(x, y)” 的形式。
○ 重写 __repr__
方法,使其返回一个可以用于重新创建对象的字符串,例如 Vector2D(x=1, y=2)
。
○ 重写 __eq__
方法,定义两个向量在 x 和 y 都相等时才相等。
○ 重写 __add__
方法,定义向量的加法(对应 + 运算符)
。
○ 创建 Vector2D 对象并测试这些重写的方法。
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 14:57
class Vector2D:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"({self.x},{self.y})"
def __repr__(self):
# 返回一个可以用于重新创建对象的字符串
return f"Vector2D(x={self.x}, y={self.y})"
def __eq__(self, other):
# 两个向量在 x 和 y 都相等时才相等
if self.x == other.x and self.y == other.y:
return True
return False
def __add__(self, other):
# 向量的加法(对应 + 运算符)
self.x += other.x
self.y += other.y
# 测试
v1 = Vector2D(2, 3)
v2 = Vector2D(10, 20)
v3 = Vector2D(2, 3)
print(v1)
print(repr(v2))
# 获取对象的 __repr__ 字符串表示
format2 = repr(v2)
# 使用 eval() 函数从字符串重新创建对象
try:
vec2 = eval(format2)
print(f"从字符串创建的新对象: {vec2}")
# 4. 验证新对象和原始对象是否相等 (需要 __eq__ 方法)
if v2 == vec2:
print("验证成功: 新对象与原始对象相等!")
else:
print("验证失败: 新对象与原始对象不相等。")
except NameError as e:
print(f"错误:无法执行 eval。确保 Vector2D 类在 eval 环境中可见。({e})")
except Exception as e:
print(f"执行 eval 时发生意外错误: {e}")
print(f"v1 == v3:{v1.__eq__(v3)}")
v1.__add__(v2)
print(f"v1 + v2后的v1:{v1}")
习题4.2
创建一个 Product 类,包含 id (产品ID) 和 name (产品名称) 属性。
○ 重写 __hash__
方法,使得两个 Product 对象只要 id 相同,就被认为是相同的哈希值。
○ 重写 __eq__
方法,使得两个 Product 对象只要 id 相同,就被认为是相等的。
○ 创建一个字典,使用 Product 对象作为键,并测试其行为。
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 15:16
class Product:
def __init__(self, id, name):
"""
id (产品ID) 和 name (产品名称) 属性
"""
self.id = id
self.name = name
print(f"产品{self.id}-{self.name}被创建...")
def __hash__(self):
"""
两个 Product 对象只要 id 相同,就被认为是相同的哈希值
"""
return hash(self.id)
def __eq__(self, other):
"""
两个 Product 对象只要 id 相同,就被认为是相等的。
"""
return self.id == other.id
# 创建一个字典,使用 Product 对象作为键,并测试其行为
dict1 = {Product(1, "苹果"): "a", Product(1, "香蕉"): "b", Product(2, "西瓜"): "c", Product(3, "哈密瓜"): "d"}
print(len(dict1))
多态
习题5.1
创建一个函数 process_vehicle(vehicle)
,它接受一个 vehicle 对象。
○ 如果 vehicle 对象有 drive() 方法,就调用它。
○ 如果 vehicle 对象有 sail() 方法,就调用它。
○ 如果 vehicle 对象有 fly() 方法,就调用它。
○ 创建 Car、Boat 和 Airplane 三个类,它们分别实现各自的 drive()、sail()、fly() 方法。
○ 创建 AmphibiousVehicle 类,同时实现 drive() 和 sail() 方法。
○ 创建这些类的对象,并使用 process_vehicle
函数处理它们。
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 15:53
# 创建 Car、Boat 和 Airplane 三个类,它们分别实现各自的 drive()、sail()、fly() 方法
class Car:
def drive(self):
print("汽车drive开一开...")
def sail(self):
print("汽车sail不了...")
def fly(self):
print("汽车fly不了...")
class Boat:
def drive(self):
print("船可以drive吗...")
def sail(self):
print("船勇敢sail...")
def fly(self):
print("船无法sail吧...")
class Airplane:
def drive(self):
print("飞机可以drive吗...")
def sail(self):
print("飞机不能sail吧...")
def fly(self):
print("飞机勇敢fly...")
# 创建 AmphibiousVehicle 类,同时实现 drive() 和 sail() 方法
class AmphibiousVehicle:
def drive(self):
print("AmphibiousVehicle的Drive方法被调用了...")
def sail(self):
print("AmphibiousVehicle的sail方法被调用了...")
def process_vehicle(vehicle):
if hasattr(vehicle, "drive"):
vehicle.drive()
if hasattr(vehicle, "sail"):
vehicle.sail()
if hasattr(vehicle, "fly"):
vehicle.fly()
car = Car()
boat = Boat()
ap = Airplane()
amphibiousVehicle = AmphibiousVehicle()
set1 = {car, boat, ap, amphibiousVehicle}
for i in set1:
process_vehicle(i)
习题 5.2 (抽象基类)
创建一个抽象基类 PaymentMethod,包含一个抽象方法 process_payment(amount)
。
○ 创建 CreditCardPayment 子类,实现 process_payment
方法,模拟信用卡支付逻辑。
○ 创建 PayPalPayment 子类,实现 process_payment
方法,模拟PayPal支付逻辑。
○ 创建一个函数 checkout(payment_method, total_amount)
,接收一个 PaymentMethod 类型的对象和一个金额,然后调用其 process_payment
方法。
○ 尝试实例化 PaymentMethod 类,观察是否报错。
○ 创建 CreditCardPayment 和 PayPalPayment 对象,并使用 checkout 函数进行支付。
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
# 博客地址: https://kirsten-1.github.io/
# 创建者: kirsten-1
# 时间: 2025/7/8 16:01
import abc
class PaymentMethod(abc.ABC):
@abc.abstractmethod
def process_payment(self, amount):
pass
class CreditCardPayment(PaymentMethod):
def process_payment(self, amount):
print(f"信用卡支付{amount}元")
class PayPalPayment(PaymentMethod):
def process_payment(self, amount):
print(f"Paypal支付{amount}元")
def checkout(payment_method, total_amount):
payment_method.process_payment(total_amount)
try:
pm = PaymentMethod()
except TypeError as e:
print(f"报错:{e}")
ccp = CreditCardPayment()
ppp = PayPalPayment()
dict1 = {ccp: 200, ppp: 300}
for i in dict1.items():
checkout(i[0], i[1])