Appearance
Python 面向对象编程(OOP)
面向对象编程是一种以对象为核心的编程范式,通过类来定义对象的属性和行为。
1. 类与对象
1.1 基本概念
- 类(Class):对象的模板/蓝图,定义了属性和方法
- 对象(Object):类的实例,拥有具体的数据
python
# 定义一个最简单的类
class Dog:
pass
# 创建对象(实例化)
d1 = Dog()
d2 = Dog()
print(type(d1)) # <class '__main__.Dog'>
print(isinstance(d1, Dog)) # True
print(d1 is d2) # False (两个不同的对象)1.2 __init__ 与实例属性
__init__ 是初始化方法,在创建对象时自动调用。self 代表当前实例本身。
python
class Dog:
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
def bark(self): # 实例方法
print(f"{self.name} 说:汪汪!")
def info(self):
print(f"名字:{self.name},年龄:{self.age}岁")
# 创建对象
dog1 = Dog("旺财", 3)
dog2 = Dog("小白", 1)
dog1.bark() # 旺财 说:汪汪!
dog2.bark() # 小白 说:汪汪!
dog1.info() # 名字:旺财,年龄:3岁
# 访问和修改属性
print(dog1.name) # 旺财
dog1.age = 4
dog1.info() # 名字:旺财,年龄:4岁
# 动态添加属性(仅对当前实例生效)
dog1.color = "黄色"
print(dog1.color) # 黄色
# print(dog2.color) # ❌ AttributeError1.3 类属性 vs 实例属性
python
class Cat:
species = "猫科动物" # 类属性,所有实例共享
count = 0
def __init__(self, name):
self.name = name # 实例属性,每个实例独有
Cat.count += 1 # 通过类名修改类属性
c1 = Cat("小花")
c2 = Cat("小黑")
# 类属性通过类或实例都能访问
print(Cat.species) # 猫科动物
print(c1.species) # 猫科动物
print(c2.species) # 猫科动物
print(Cat.count) # 2
# ⚠️ 通过实例赋值会创建同名实例属性,不会修改类属性
c1.species = "猫猫"
print(c1.species) # 猫猫 (实例属性,遮蔽了类属性)
print(c2.species) # 猫科动物(类属性不受影响)
print(Cat.species) # 猫科动物(类属性不受影响)2. 方法类型
2.1 实例方法、类方法、静态方法
python
class MyClass:
class_var = "我是类变量"
def __init__(self, value):
self.value = value
# 实例方法:第一个参数是 self(实例)
def instance_method(self):
print(f"实例方法,访问实例属性:{self.value}")
print(f"实例方法,也能访问类属性:{MyClass.class_var}")
# 类方法:第一个参数是 cls(类本身)
@classmethod
def class_method(cls):
print(f"类方法,访问类属性:{cls.class_var}")
# print(cls.value) # ❌ 不能访问实例属性
# 静态方法:没有 self 也没有 cls,和普通函数一样
@staticmethod
def static_method(x, y):
print(f"静态方法,计算结果:{x + y}")
obj = MyClass(42)
# 实例方法:通过实例调用
obj.instance_method()
# 实例方法,访问实例属性:42
# 实例方法,也能访问类属性:我是类变量
# 类方法:通过类或实例调用
MyClass.class_method() # 类方法,访问类属性:我是类变量
obj.class_method() # 类方法,访问类属性:我是类变量
# 静态方法:通过类或实例调用
MyClass.static_method(3, 5) # 静态方法,计算结果:8
obj.static_method(3, 5) # 静态方法,计算结果:82.2 类方法的常见用途 —— 替代构造函数
python
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __str__(self):
return f"{self.year}-{self.month:02d}-{self.day:02d}"
@classmethod
def from_string(cls, date_str):
"""从字符串创建日期:'2024-01-15'"""
year, month, day = map(int, date_str.split("-"))
return cls(year, month, day)
@classmethod
def today(cls):
"""创建今天的日期"""
import datetime
t = datetime.date.today()
return cls(t.year, t.month, t.day)
# 不同方式创建对象
d1 = Date(2024, 1, 15)
d2 = Date.from_string("2024-06-20")
d3 = Date.today()
print(d1) # 2024-01-15
print(d2) # 2024-06-20
print(d3) # 2026-03-17(当天日期)3. 封装
3.1 访问控制约定
Python 没有真正的私有,而是通过命名约定来表示访问级别。
python
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner # 公开属性
self._type = "储蓄" # 受保护属性(约定,不强制)
self.__balance = balance # 私有属性(名称改写)
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"存入 {amount},余额:{self.__balance}")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"取出 {amount},余额:{self.__balance}")
else:
print("余额不足或金额无效")
def get_balance(self):
return self.__balance
acc = BankAccount("Alice", 1000)
# 公开属性:随意访问
print(acc.owner) # Alice
# 受保护属性:可以访问,但约定不建议外部使用
print(acc._type) # 储蓄
# 私有属性:不能直接访问
# print(acc.__balance) # ❌ AttributeError
# 通过公开方法访问
print(acc.get_balance()) # 1000
acc.deposit(500) # 存入 500,余额:1500
acc.withdraw(200) # 取出 200,余额:1300
# ⚠️ 其实可以通过名称改写访问(但强烈不推荐)
print(acc._BankAccount__balance) # 13003.2 @property 属性装饰器
将方法伪装成属性,实现受控的读写访问。
python
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""获取半径"""
return self._radius
@radius.setter
def radius(self, value):
"""设置半径(带校验)"""
if value <= 0:
raise ValueError("半径必须大于 0")
self._radius = value
@property
def area(self):
"""面积(只读属性,没有 setter)"""
import math
return math.pi * self._radius ** 2
@property
def perimeter(self):
"""周长(只读)"""
import math
return 2 * math.pi * self._radius
c = Circle(5)
# 像访问属性一样使用(不需要加括号)
print(c.radius) # 5
print(f"{c.area:.2f}") # 78.54
print(f"{c.perimeter:.2f}") # 31.42
# 设置属性(触发 setter 校验)
c.radius = 10
print(c.radius) # 10
print(f"{c.area:.2f}") # 314.16
# 校验生效
try:
c.radius = -1
except ValueError as e:
print(e) # 半径必须大于 0
# 只读属性不能赋值
# c.area = 100 # ❌ AttributeError: property 'area' has no setter4. 继承
4.1 基本继承
python
# 父类(基类)
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self):
print(f"{self.name} 发出了声音")
def info(self):
print(f"[{self.__class__.__name__}] {self.name},{self.age}岁")
# 子类(派生类)
class Dog(Animal):
def __init__(self, name, age, breed):
super().__init__(name, age) # 调用父类的 __init__
self.breed = breed
def speak(self): # 方法重写(Override)
print(f"{self.name} 说:汪汪!")
def fetch(self): # 子类独有的方法
print(f"{self.name} 在捡球")
class Cat(Animal):
def speak(self):
print(f"{self.name} 说:喵喵~")
# 使用
dog = Dog("旺财", 3, "柴犬")
cat = Cat("小花", 2)
dog.speak() # 旺财 说:汪汪!
cat.speak() # 小花 说:喵喵~
dog.info() # [Dog] 旺财,3岁
cat.info() # [Cat] 小花,2岁
dog.fetch() # 旺财 在捡球
# cat.fetch() # ❌ AttributeError(Cat 没有 fetch 方法)
# 继承关系判断
print(isinstance(dog, Dog)) # True
print(isinstance(dog, Animal)) # True (Dog 是 Animal 的子类)
print(isinstance(cat, Dog)) # False
print(issubclass(Dog, Animal)) # True
print(issubclass(Cat, Animal)) # True
print(issubclass(Dog, Cat)) # False4.2 多态
同一个方法在不同子类中有不同的行为。
python
class Shape:
def area(self):
raise NotImplementedError("子类必须实现 area 方法")
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):
import math
return math.pi * self.radius ** 2
class Triangle(Shape):
def __init__(self, base, height):
self.base = base
self.height = height
def area(self):
return 0.5 * self.base * self.height
# 多态:同一个函数处理不同类型的对象
def print_area(shape: Shape):
print(f"{shape.__class__.__name__} 的面积:{shape.area():.2f}")
shapes = [Rectangle(4, 5), Circle(3), Triangle(6, 8)]
for s in shapes:
print_area(s)
# Rectangle 的面积:20.00
# Circle 的面积:28.27
# Triangle 的面积:24.004.3 多继承与 MRO
python
class A:
def greet(self):
print("来自 A")
class B(A):
def greet(self):
print("来自 B")
class C(A):
def greet(self):
print("来自 C")
class D(B, C): # 多继承
pass
d = D()
d.greet() # 来自 B
# MRO(方法解析顺序):决定多继承时方法的查找顺序
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)
# Python 使用 C3 线性化算法,顺序:D → B → C → A → object
# super() 在多继承中沿 MRO 顺序调用
class A:
def __init__(self):
print("A.__init__")
class B(A):
def __init__(self):
print("B.__init__")
super().__init__() # 沿 MRO 调用下一个
class C(A):
def __init__(self):
print("C.__init__")
super().__init__()
class D(B, C):
def __init__(self):
print("D.__init__")
super().__init__()
D()
# D.__init__
# B.__init__
# C.__init__
# A.__init__4.4 Mixin 模式
Mixin 是一种通过多继承为类添加功能的设计模式。
python
# Mixin 类:提供可复用的功能
class JsonMixin:
def to_json(self):
import json
return json.dumps(self.__dict__, ensure_ascii=False)
class PrintMixin:
def print_info(self):
attrs = ", ".join(f"{k}={v}" for k, v in self.__dict__.items())
print(f"{self.__class__.__name__}({attrs})")
# 通过多继承组合功能
class User(JsonMixin, PrintMixin):
def __init__(self, name, age):
self.name = name
self.age = age
class Product(JsonMixin, PrintMixin):
def __init__(self, title, price):
self.title = title
self.price = price
user = User("Alice", 25)
user.print_info() # User(name=Alice, age=25)
print(user.to_json()) # {"name": "Alice", "age": 25}
product = Product("Python书", 59.9)
product.print_info() # Product(title=Python书, price=59.9)
print(product.to_json()) # {"title": "Python书", "price": 59.9}5. 魔术方法(双下方法)
魔术方法以双下划线开头和结尾(__xxx__),让自定义类支持 Python 的内置操作。
5.1 字符串表示
python
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
"""print() 和 str() 调用,面向用户"""
return f"({self.x}, {self.y})"
def __repr__(self):
"""repr() 调用,面向开发者,应能重建对象"""
return f"Point({self.x}, {self.y})"
p = Point(3, 4)
print(p) # (3, 4) ← __str__
print(repr(p)) # Point(3, 4) ← __repr__
print(f"坐标是 {p}") # 坐标是 (3, 4) ← f-string 调用 __str__
# 在列表中展示时用 __repr__
points = [Point(1, 2), Point(3, 4)]
print(points) # [Point(1, 2), Point(3, 4)] ← 列表中用 __repr__5.2 比较运算
python
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __repr__(self):
return f"Student({self.name!r}, {self.score})"
def __eq__(self, other):
if not isinstance(other, Student):
return NotImplemented
return self.score == other.score
def __lt__(self, other):
if not isinstance(other, Student):
return NotImplemented
return self.score < other.score
def __le__(self, other):
return self == other or self < other
s1 = Student("Alice", 90)
s2 = Student("Bob", 85)
s3 = Student("Charlie", 90)
print(s1 == s3) # True (分数相同)
print(s1 == s2) # False
print(s2 < s1) # True (85 < 90)
print(s1 <= s3) # True
# 支持排序
students = [s1, s2, s3]
students.sort()
print(students) # [Student('Bob', 85), Student('Alice', 90), Student('Charlie', 90)]
# 💡 用 functools.total_ordering 可以少写比较方法
from functools import total_ordering
@total_ordering
class Score:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
def __lt__(self, other):
return self.value < other.value
# 自动生成 __le__、__gt__、__ge__5.3 算术运算
python
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Vector({self.x}, {self.y})"
def __add__(self, other):
"""v1 + v2"""
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
"""v1 - v2"""
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
"""v * 数字"""
return Vector(self.x * scalar, self.y * scalar)
def __rmul__(self, scalar):
"""数字 * v(反向乘法)"""
return self.__mul__(scalar)
def __abs__(self):
"""abs(v) 返回向量的模"""
return (self.x ** 2 + self.y ** 2) ** 0.5
def __bool__(self):
"""bool(v) 判断是否为零向量"""
return self.x != 0 or self.y != 0
def __neg__(self):
"""-v"""
return Vector(-self.x, -self.y)
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(v1 + v2) # Vector(4, 6)
print(v1 - v2) # Vector(2, 2)
print(v1 * 3) # Vector(9, 12)
print(2 * v1) # Vector(6, 8) ← __rmul__
print(abs(v1)) # 5.0
print(-v1) # Vector(-3, -4)
print(bool(v1)) # True
print(bool(Vector(0, 0))) # False5.4 容器协议
让自定义类像列表/字典一样工作。
python
class Playlist:
def __init__(self, name, songs=None):
self.name = name
self._songs = list(songs) if songs else []
def __len__(self):
"""len(playlist)"""
return len(self._songs)
def __getitem__(self, index):
"""playlist[i] 或 playlist[start:end]"""
return self._songs[index]
def __setitem__(self, index, value):
"""playlist[i] = value"""
self._songs[index] = value
def __delitem__(self, index):
"""del playlist[i]"""
del self._songs[index]
def __contains__(self, item):
"""item in playlist"""
return item in self._songs
def __iter__(self):
"""for song in playlist"""
return iter(self._songs)
def __repr__(self):
return f"Playlist({self.name!r}, {self._songs})"
pl = Playlist("我的歌单", ["稻香", "晴天", "夜曲"])
# 长度
print(len(pl)) # 3
# 索引访问
print(pl[0]) # 稻香
print(pl[-1]) # 夜曲
print(pl[0:2]) # ['稻香', '晴天']
# 修改
pl[1] = "七里香"
print(pl) # Playlist('我的歌单', ['稻香', '七里香', '夜曲'])
# 删除
del pl[0]
print(pl) # Playlist('我的歌单', ['七里香', '夜曲'])
# 成员判断
print("夜曲" in pl) # True
print("晴天" in pl) # False
# 遍历
for song in pl:
print(f"♪ {song}")
# ♪ 七里香
# ♪ 夜曲5.5 可调用对象
python
class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
"""让实例可以像函数一样调用"""
return self.n + x
add5 = Adder(5)
add10 = Adder(10)
# 像调用函数一样使用
print(add5(3)) # 8
print(add10(3)) # 13
print(callable(add5)) # True
# 实用示例:带状态的计数器
class Counter:
def __init__(self):
self.count = 0
def __call__(self):
self.count += 1
return self.count
c = Counter()
print(c()) # 1
print(c()) # 2
print(c()) # 3
print(c.count) # 35.6 上下文管理器
python
class FileManager:
def __init__(self, filename, mode="r"):
self.filename = filename
self.mode = mode
self.file = None
def __enter__(self):
"""进入 with 块时调用"""
print(f"打开文件:{self.filename}")
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
"""离开 with 块时调用(无论是否异常)"""
print(f"关闭文件:{self.filename}")
if self.file:
self.file.close()
return False # False 表示不抑制异常
# 使用
with FileManager("test.txt", "w") as f:
f.write("Hello, Python!")
# 打开文件:test.txt
# 关闭文件:test.txt
# 实用示例:计时器
import time
class Timer:
def __enter__(self):
self.start = time.time()
return self
def __exit__(self, *args):
self.elapsed = time.time() - self.start
print(f"耗时:{self.elapsed:.4f}秒")
with Timer():
total = sum(range(1_000_000))
# 耗时:0.0234秒5.7 常用魔术方法总结
| 方法 | 触发方式 | 说明 |
|---|---|---|
__init__(self, ...) | MyClass() | 初始化 |
__str__(self) | print(obj) / str(obj) | 用户友好的字符串 |
__repr__(self) | repr(obj) | 开发者友好的字符串 |
__len__(self) | len(obj) | 长度 |
__getitem__(self, key) | obj[key] | 索引访问 |
__setitem__(self, key, val) | obj[key] = val | 索引赋值 |
__delitem__(self, key) | del obj[key] | 索引删除 |
__contains__(self, item) | item in obj | 成员判断 |
__iter__(self) | for x in obj | 迭代 |
__next__(self) | next(obj) | 下一个元素 |
__call__(self, ...) | obj() | 像函数一样调用 |
__eq__(self, other) | obj == other | 等于 |
__lt__(self, other) | obj < other | 小于 |
__add__(self, other) | obj + other | 加法 |
__mul__(self, other) | obj * other | 乘法 |
__enter__ / __exit__ | with obj | 上下文管理 |
__hash__(self) | hash(obj) | 哈希值 |
__bool__(self) | bool(obj) | 布尔转换 |
6. 抽象基类(ABC)
抽象基类定义接口规范,强制子类实现指定方法。
python
from abc import ABC, abstractmethod
class Animal(ABC):
def __init__(self, name):
self.name = name
@abstractmethod
def speak(self):
"""子类必须实现此方法"""
pass
@abstractmethod
def move(self):
pass
def sleep(self):
"""普通方法,子类可以直接使用"""
print(f"{self.name} 正在睡觉 💤")
# 抽象类不能实例化
# a = Animal("test") # ❌ TypeError: Can't instantiate abstract class
class Dog(Animal):
def speak(self):
print(f"{self.name}:汪汪!")
def move(self):
print(f"{self.name} 在跑")
class Fish(Animal):
def speak(self):
print(f"{self.name}:...(鱼不会说话)")
def move(self):
print(f"{self.name} 在游泳")
dog = Dog("旺财")
fish = Fish("尼莫")
dog.speak() # 旺财:汪汪!
dog.move() # 旺财 在跑
dog.sleep() # 旺财 正在睡觉 💤
fish.speak() # 尼莫:...(鱼不会说话)
fish.move() # 尼莫 在游泳
# 如果子类没有实现抽象方法,实例化时报错
# class Bird(Animal):
# def speak(self):
# print("叽叽")
# # 没有实现 move()
# Bird("小鸟") # ❌ TypeError: Can't instantiate abstract class Bird7. 数据类(dataclass)
@dataclass 自动生成 __init__、__repr__、__eq__ 等方法,减少样板代码。
python
from dataclasses import dataclass, field
# 基本用法
@dataclass
class Point:
x: float
y: float
p1 = Point(3, 4)
p2 = Point(3, 4)
p3 = Point(1, 2)
print(p1) # Point(x=3, y=4) ← 自动生成 __repr__
print(p1 == p2) # True ← 自动生成 __eq__
print(p1 == p3) # False
# 带默认值
@dataclass
class User:
name: str
age: int = 0
email: str = ""
tags: list = field(default_factory=list) # 可变默认值用 field
u = User("Alice", 25)
print(u) # User(name='Alice', age=25, email='', tags=[])
u.tags.append("python")
print(u.tags) # ['python']
# 冻结的数据类(不可变)
@dataclass(frozen=True)
class Color:
r: int
g: int
b: int
red = Color(255, 0, 0)
print(red) # Color(r=255, g=0, b=0)
# red.r = 100 # ❌ FrozenInstanceError
# frozen 的数据类可以作为字典的键
colors = {Color(255, 0, 0): "红色", Color(0, 255, 0): "绿色"}
print(colors[Color(255, 0, 0)]) # 红色
# 排序支持
@dataclass(order=True)
class Student:
score: float
name: str = ""
students = [Student(85, "Bob"), Student(92, "Alice"), Student(85, "Charlie")]
students.sort()
for s in students:
print(s)
# Student(score=85, name='Bob')
# Student(score=85, name='Charlie')
# Student(score=92, name='Alice')
# __post_init__ 后处理
@dataclass
class Rectangle:
width: float
height: float
area: float = field(init=False) # 不在 __init__ 参数中
def __post_init__(self):
self.area = self.width * self.height
r = Rectangle(4, 5)
print(r) # Rectangle(width=4, height=5, area=20)
print(r.area) # 208. 枚举类(Enum)
用于定义一组有名字的常量。
python
from enum import Enum, auto
class Color(Enum):
RED = 1
GREEN = 2
BLUE = 3
# 访问枚举成员
print(Color.RED) # Color.RED
print(Color.RED.name) # RED
print(Color.RED.value) # 1
print(repr(Color.RED)) # <Color.RED: 1>
# 通过值或名称获取
print(Color(1)) # Color.RED
print(Color["GREEN"]) # Color.GREEN
# 比较
print(Color.RED == Color.RED) # True
print(Color.RED == Color.BLUE) # False
print(Color.RED is Color.RED) # True
# print(Color.RED < Color.BLUE) # ❌ TypeError(Enum 不支持大小比较)
# 遍历
for color in Color:
print(f"{color.name} = {color.value}")
# RED = 1
# GREEN = 2
# BLUE = 3
# auto() 自动赋值
class Direction(Enum):
NORTH = auto()
SOUTH = auto()
EAST = auto()
WEST = auto()
print(list(Direction))
# [<Direction.NORTH: 1>, <Direction.SOUTH: 2>, <Direction.EAST: 3>, <Direction.WEST: 4>]
# 实际应用
class Status(Enum):
PENDING = "pending"
RUNNING = "running"
SUCCESS = "success"
FAILED = "failed"
def handle_task(status: Status):
match status:
case Status.PENDING:
print("等待中...")
case Status.RUNNING:
print("运行中...")
case Status.SUCCESS:
print("已完成!")
case Status.FAILED:
print("失败!")
handle_task(Status.SUCCESS) # 已完成!9. __slots__ 优化
默认情况下,Python 对象使用 __dict__ 存储属性,灵活但占用更多内存。使用 __slots__ 可以限制属性并节省内存。
python
class PointDict:
"""普通类,使用 __dict__"""
def __init__(self, x, y):
self.x = x
self.y = y
class PointSlots:
"""使用 __slots__ 优化"""
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x = x
self.y = y
p1 = PointDict(1, 2)
p2 = PointSlots(1, 2)
# 功能相同
print(p1.x, p1.y) # 1 2
print(p2.x, p2.y) # 1 2
# __dict__ 存在与否
print(p1.__dict__) # {'x': 1, 'y': 2}
# print(p2.__dict__) # ❌ AttributeError
# __slots__ 不允许动态添加属性
p1.z = 3 # ✅ 普通类可以
# p2.z = 3 # ❌ AttributeError: 'PointSlots' object has no attribute 'z'
# 内存对比
import sys
print(sys.getsizeof(p1.__dict__)) # 104(__dict__ 本身的开销)
# PointSlots 没有 __dict__,更省内存
# 当创建大量对象时(如 100 万个),差异非常明显10. 综合示例
示例 1:简易购物车
python
@dataclass
class Product:
name: str
price: float
class ShoppingCart:
def __init__(self):
self._items: list[tuple[Product, int]] = []
def add(self, product: Product, qty: int = 1):
for i, (p, q) in enumerate(self._items):
if p.name == product.name:
self._items[i] = (p, q + qty)
return
self._items.append((product, qty))
def total(self) -> float:
return sum(p.price * q for p, q in self._items)
def __len__(self):
return sum(q for _, q in self._items)
def __str__(self):
lines = [f" {p.name} × {q} = ¥{p.price * q:.2f}"
for p, q in self._items]
return "购物车:\n" + "\n".join(lines) + f"\n 合计:¥{self.total():.2f}"
cart = ShoppingCart()
cart.add(Product("Python书", 59.9), 2)
cart.add(Product("键盘", 299.0))
cart.add(Product("鼠标", 79.0))
print(cart)
# 购物车:
# Python书 × 2 = ¥119.80
# 键盘 × 1 = ¥299.00
# 鼠标 × 1 = ¥79.00
# 合计:¥497.80
print(f"共 {len(cart)} 件商品") # 共 4 件商品示例 2:链式调用(Builder 模式)
python
class QueryBuilder:
def __init__(self, table):
self._table = table
self._conditions = []
self._order = None
self._limit = None
def where(self, condition):
self._conditions.append(condition)
return self # 返回 self 实现链式调用
def order_by(self, field, desc=False):
direction = "DESC" if desc else "ASC"
self._order = f"{field} {direction}"
return self
def limit(self, n):
self._limit = n
return self
def build(self):
sql = f"SELECT * FROM {self._table}"
if self._conditions:
sql += " WHERE " + " AND ".join(self._conditions)
if self._order:
sql += f" ORDER BY {self._order}"
if self._limit:
sql += f" LIMIT {self._limit}"
return sql
# 链式调用
sql = (QueryBuilder("users")
.where("age > 18")
.where("status = 'active'")
.order_by("created_at", desc=True)
.limit(10)
.build())
print(sql)
# SELECT * FROM users WHERE age > 18 AND status = 'active' ORDER BY created_at DESC LIMIT 10示例 3:观察者模式(事件系统)
python
class EventEmitter:
def __init__(self):
self._listeners: dict[str, list] = {}
def on(self, event: str, callback):
"""注册监听器"""
self._listeners.setdefault(event, []).append(callback)
def emit(self, event: str, *args, **kwargs):
"""触发事件"""
for callback in self._listeners.get(event, []):
callback(*args, **kwargs)
# 使用
emitter = EventEmitter()
# 注册事件监听
emitter.on("login", lambda user: print(f"[日志] {user} 登录了"))
emitter.on("login", lambda user: print(f"[通知] 欢迎回来,{user}!"))
emitter.on("error", lambda msg: print(f"[错误] {msg}"))
# 触发事件
emitter.emit("login", "Alice")
# [日志] Alice 登录了
# [通知] 欢迎回来,Alice!
emitter.emit("error", "数据库连接失败")
# [错误] 数据库连接失败11. 总结
| 概念 | 说明 | 关键字/语法 |
|---|---|---|
| 类与对象 | 类是模板,对象是实例 | class、self、__init__ |
| 实例方法 | 操作实例数据 | def method(self) |
| 类方法 | 操作类级别数据 | @classmethod、cls |
| 静态方法 | 与类相关的工具函数 | @staticmethod |
| 封装 | 控制属性访问 | _、__、@property |
| 继承 | 复用父类代码 | class Child(Parent)、super() |
| 多态 | 同名方法不同行为 | 方法重写 |
| 抽象基类 | 定义接口规范 | ABC、@abstractmethod |
| 魔术方法 | 支持内置操作 | __str__、__add__、__len__ 等 |
| 数据类 | 减少样板代码 | @dataclass |
| 枚举类 | 定义命名常量 | Enum、auto() |
__slots__ | 限制属性,节省内存 | __slots__ = (...) |
OOP 设计原则
python
# 1. 单一职责:一个类只负责一件事
# 2. 开闭原则:对扩展开放,对修改关闭(用继承/多态扩展,不改已有代码)
# 3. 里氏替换:子类对象能替换父类对象使用
# 4. 组合优于继承:优先用"有一个"(组合)而非"是一个"(继承)
# ✅ 组合
class Engine:
def start(self):
print("引擎启动")
class Car:
def __init__(self):
self.engine = Engine() # Car "有一个" Engine
def start(self):
self.engine.start()
print("汽车出发")
car = Car()
car.start()
# 引擎启动
# 汽车出发
# ❌ 不好的继承(Car 不应该 "是一个" Engine)
# class Car(Engine):
# pass