Python 面向对象高级

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) # Vector(4, 6)
print(v1 - v2) # Vector(-2, -2)
print(v1 * 3) # Vector(3, 6)
print(v1 == v2) # False
print(len(v1)) # 2
print(v1[0]) # 1

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) # True
print(s1 > s2) # False
print(s1 <= s2) # True

16.3 slots

__slots__ 限制实例属性,节省内存。

1
2
3
4
5
6
7
8
9
10
class Point:
__slots__ = ["x", "y"] # 只能有 x 和 y 属性

def __init__(self, x, y):
self.x = x
self.y = y

p = Point(1, 2)
p.x = 10
# p.z = 30 # AttributeError: 'Point' object has no attribute 'z'

适用场景

  • 创建大量实例时节省内存
  • 防止意外添加属性
  • 不适用于需要动态添加属性的场景

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

# shape = Shape() # TypeError: 不能实例化抽象类
rect = Rectangle(5, 3)
circle = Circle(4)

print(rect.area()) # 15
print(circle.perimeter()) # 25.13...

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) # 10
# p.price = -5 # ValueError

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() # Hello, Alice!

自定义元类

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
# 输出: 创建类: MyClass

16.8 本章小结

  • 魔术方法定义类的行为(__init____str____add__ 等)
  • 运算符重载实现自定义操作
  • __slots__ 限制属性,节省内存
  • 抽象基类强制子类实现接口
  • 描述符控制属性访问
  • 上下文管理器实现资源自动管理
  • 元类用于高级类定制

练习题

  1. 创建 Matrix 类,实现矩阵加法
  2. 使用抽象基类定义 Payment 接口,实现 CreditCardPayPal
  3. 创建上下文管理器实现数据库连接管理
  4. 以下代码输出什么?
    1
    2
    3
    4
    5
    class A:
    def __str__(self):
    return "A"
    a = A()
    print(a)
ByteFisher
分享编程技术 · 记录钓鱼乐趣
扫码关注
▸ 扫码关注 ◂
Python基础教程 系列
第 16/20 篇
分享: