16.1 魔术方法
魔术方法是以双下划线开头和结尾的特殊方法,用于定义类的行为。
常用魔术方法
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
| class Vector: def __init__(self, x, y): self.x = x self.y = y def __str__(self): return f"Vector({self.x}, {self.y})" def __repr__(self): return f"Vector({self.x}, {self.y})" def __add__(self, other): return Vector(self.x + other.x, self.y + other.y) def __sub__(self, other): return Vector(self.x - other.x, self.y - other.y) def __mul__(self, scalar): return Vector(self.x * scalar, self.y * scalar) def __eq__(self, other): return self.x == other.x and self.y == other.y def __len__(self): return 2 def __getitem__(self, index): if index == 0: return self.x elif index == 1: return self.y raise IndexError("索引越界")
v1 = Vector(1, 2) v2 = Vector(3, 4)
print(v1 + v2) print(v1 - v2) print(v1 * 3) print(v1 == v2) print(len(v1)) print(v1[0])
|
16.2 运算符重载
通过魔术方法实现自定义运算符。
比较运算符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Student: def __init__(self, name, score): self.name = name self.score = score def __lt__(self, other): return self.score < other.score def __le__(self, other): return self.score <= other.score def __gt__(self, other): return self.score > other.score def __ge__(self, other): return self.score >= other.score
s1 = Student("Alice", 85) s2 = Student("Bob", 90)
print(s1 < s2) print(s1 > s2) print(s1 <= s2)
|
16.3 slots
__slots__ 限制实例属性,节省内存。
1 2 3 4 5 6 7 8 9 10
| class Point: __slots__ = ["x", "y"] def __init__(self, x, y): self.x = x self.y = y
p = Point(1, 2) p.x = 10
|
适用场景
- 创建大量实例时节省内存
- 防止意外添加属性
- 不适用于需要动态添加属性的场景
16.4 抽象基类
抽象基类定义接口,强制子类实现特定方法。
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
| from abc import ABC, abstractmethod
class Shape(ABC): @abstractmethod def area(self): pass @abstractmethod def perimeter(self): pass
class Rectangle(Shape): def __init__(self, width, height): self.width = width self.height = height def area(self): return self.width * self.height def perimeter(self): return 2 * (self.width + self.height)
class Circle(Shape): def __init__(self, radius): self.radius = radius def area(self): import math return math.pi * self.radius ** 2 def perimeter(self): import math return 2 * math.pi * self.radius
rect = Rectangle(5, 3) circle = Circle(4)
print(rect.area()) print(circle.perimeter())
|
16.5 描述符
描述符是控制属性访问的类。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class PositiveNumber: def __set_name__(self, owner, name): self.name = name def __get__(self, obj, objtype=None): return getattr(obj, self.name) def __set__(self, obj, value): if value <= 0: raise ValueError(f"{self.name} 必须大于 0") setattr(obj, self.name, value)
class Product: price = PositiveNumber() quantity = PositiveNumber() def __init__(self, price, quantity): self.price = price self.quantity = quantity
p = Product(10, 5) print(p.price)
|
16.6 上下文管理器
实现 __enter__ 和 __exit__ 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class FileManager: def __init__(self, filename, mode): self.filename = filename self.mode = mode def __enter__(self): self.file = open(self.filename, self.mode) return self.file def __exit__(self, exc_type, exc_val, exc_tb): self.file.close()
with FileManager("test.txt", "w") as f: f.write("Hello!")
|
使用 contextlib
1 2 3 4 5 6 7 8 9 10 11 12
| from contextlib import contextmanager
@contextmanager def open_file(filename, mode): f = open(filename, mode) try: yield f finally: f.close()
with open_file("test.txt", "r") as f: content = f.read()
|
16.7 元类简介
元类是创建类的类,type 是默认元类。
1 2 3 4 5 6 7 8 9 10 11
| def init(self, name): self.name = name
def greet(self): print(f"Hello, {self.name}!")
Person = type("Person", (), {"__init__": init, "greet": greet})
p = Person("Alice") p.greet()
|
自定义元类
1 2 3 4 5 6 7 8
| class Meta(type): def __new__(cls, name, bases, attrs): print(f"创建类: {name}") return super().__new__(cls, name, bases, attrs)
class MyClass(metaclass=Meta): pass
|
16.8 本章小结
- 魔术方法定义类的行为(
__init__、__str__、__add__ 等)
- 运算符重载实现自定义操作
__slots__ 限制属性,节省内存
- 抽象基类强制子类实现接口
- 描述符控制属性访问
- 上下文管理器实现资源自动管理
- 元类用于高级类定制
练习题
- 创建
Matrix 类,实现矩阵加法
- 使用抽象基类定义
Payment 接口,实现 CreditCard 和 PayPal
- 创建上下文管理器实现数据库连接管理
- 以下代码输出什么?
1 2 3 4 5
| class A: def __str__(self): return "A" a = A() print(a)
|