python-面向对象
Python 面向对象编程
一、面向对象编程基础
1.1 面向对象概念
- 什么是面向对象编程 (OOP)
- 一种编程范式,将现实世界的事物抽象为”对象”
- 对象包含属性(数据)和方法(行为)
- 通过对象之间的交互来构建程序
- 面向对象三大特征
- 封装:隐藏内部实现细节,提供公共接口
- 继承:子类继承父类的属性和方法,实现代码复用
- 多态:同一操作作用于不同对象产生不同的行为
- 面向对象 vs 面向过程
- 面向过程:以”函数”为中心,关注”怎么做”
- 面向对象:以”对象”为中心,关注”谁来做”
1.2 类与对象
- 类 (Class)
- 对象的蓝图或模板
- 定义对象的属性和方法
- 是抽象的数据类型
- 对象 (Object)
- 类的具体实例
- 拥有类定义的属性和方法
- 是具体的数据实例
# 定义类
class Person:
"""人类"""
pass
# 创建对象
person1 = Person() # 实例化
person2 = Person() # 另一个实例
1.3 面向对象设计原则
- 单一职责原则 (SRP):一个类只负责一个功能领域
- 开闭原则 (OCP):对扩展开放,对修改关闭
- 里氏替换原则 (LSP):子类可以替换父类
- 接口隔离原则 (ISP):使用多个专门的接口
- 依赖倒置原则 (DIP):依赖抽象,不依赖具体实现
二、类的基本结构与使用
2.1 定义类
class Person:
"""这是一个人类"""
# 类属性
species = "Human"
def __init__(self, name, age):
"""构造方法,初始化实例属性"""
self.name = name # 实例属性
self.age = age
self.__private_attr = "私有属性" # 私有属性
def say_hello(self):
"""实例方法"""
return f"Hello, I'm {self.name}, {self.age} years old."
@classmethod
def get_species(cls):
"""类方法"""
return f"Species: {cls.species}"
@staticmethod
def is_adult(age):
"""静态方法"""
return age >= 18
2.2 构造函数与初始化
__init__方法- 对象创建时自动调用
- 用于初始化对象属性
- 可以接收参数
class Student:
def __init__(self, name, age, student_id):
self.name = name
self.age = age
self.student_id = student_id
self.grades = [] # 初始化空列表
def add_grade(self, grade):
self.grades.append(grade)
def get_average(self):
if not self.grades:
return 0
return sum(self.grades) / len(self.grades)
# 使用
student = Student("张三", 20, "2023001")
student.add_grade(90)
student.add_grade(85)
print(student.get_average()) # 87.5
2.3 实例属性 vs 类属性
- 实例属性:属于具体对象,每个对象独立
- 类属性:属于类,所有对象共享
class Dog:
# 类属性
species = "Canis familiaris"
count = 0 # 记录创建的实例数量
def __init__(self, name, breed):
# 实例属性
self.name = name
self.breed = breed
Dog.count += 1 # 每次创建实例,计数器加1
def bark(self):
return f"{self.name} says Woof!"
# 测试
dog1 = Dog("Buddy", "Golden Retriever")
dog2 = Dog("Max", "German Shepherd")
print(dog1.name) # Buddy
print(dog2.name) # Max
print(dog1.species) # Canis familiaris
print(dog2.species) # Canis familiaris
print(Dog.count) # 2
2.4 方法类型
- 实例方法
- 第一个参数是
self,指向实例本身 - 可以访问和修改实例属性
- 可以访问类属性
class Calculator: def __init__(self, initial_value=0): self.value = initial_value def add(self, x): """实例方法""" self.value += x return self def multiply(self, x): """实例方法""" self.value *= x return self def get_value(self): return self.value # 链式调用 calc = Calculator(10) result = calc.add(5).multiply(2).get_value() print(result) # 30 - 第一个参数是
- 类方法
- 使用
@classmethod装饰器 - 第一个参数是
cls,指向类本身 - 可以访问和修改类属性
- 不能访问实例属性
class Circle: pi = 3.14159 def __init__(self, radius): self.radius = radius @classmethod def from_diameter(cls, diameter): """类方法:通过直径创建圆""" return cls(diameter / 2) @classmethod def get_pi(cls): """类方法:获取π值""" return cls.pi def area(self): return self.pi * self.radius ** 2 # 使用类方法创建实例 circle1 = Circle(5) circle2 = Circle.from_diameter(10) print(circle1.radius) # 5 print(circle2.radius) # 5 print(Circle.get_pi()) # 3.14159 - 使用
- 静态方法
- 使用
@staticmethod装饰器 - 没有
self或cls参数 - 与类和实例无关,只是逻辑上属于类
- 不能访问类属性和实例属性
class MathUtils: @staticmethod def add(a, b): return a + b @staticmethod def multiply(a, b): return a * b @staticmethod def factorial(n): if n == 0: return 1 return n * MathUtils.factorial(n-1) # 使用静态方法 print(MathUtils.add(5, 3)) # 8 print(MathUtils.multiply(4, 6)) # 24 print(MathUtils.factorial(5)) # 120 - 使用
三、封装
3.1 访问控制
- 公有成员:以常规方式命名,可被外部访问
- 保护成员:以单个下划线开头
_,约定为内部使用 - 私有成员:以双下划线开头
__,名称会被改写,实现伪私有
class BankAccount:
def __init__(self, owner, initial_balance=0):
self.owner = owner # 公有属性
self._balance = initial_balance # 保护属性
self.__pin = "1234" # 私有属性
def deposit(self, amount):
if amount > 0:
self._balance += amount
return True
return False
def withdraw(self, amount, pin):
if pin == self.__pin and 0 < amount <= self._balance:
self._balance -= amount
return True
return False
def get_balance(self):
return self._balance
# 测试
account = BankAccount("张三", 1000)
print(account.owner) # 张三
print(account.get_balance()) # 1000
account.deposit(500)
print(account.get_balance()) # 1500
print(account._balance) # 1500(不推荐直接访问保护属性)
# print(account.__pin) # 错误:AttributeError
print(account._BankAccount__pin) # 1234(名称被改写,但仍可访问)
3.2 属性装饰器
@property:将方法转换为只读属性@属性名.setter:设置属性的setter方法@属性名.deleter:删除属性的deleter方法
class Rectangle:
def __init__(self, width, height):
self._width = width
self._height = height
@property
def width(self):
"""获取宽度"""
return self._width
@width.setter
def width(self, value):
"""设置宽度"""
if value <= 0:
raise ValueError("宽度必须大于0")
self._width = value
@property
def height(self):
"""获取高度"""
return self._height
@height.setter
def height(self, value):
"""设置高度"""
if value <= 0:
raise ValueError("高度必须大于0")
self._height = value
@property
def area(self):
"""计算面积(只读属性)"""
return self._width * self._height
@property
def perimeter(self):
"""计算周长(只读属性)"""
return 2 * (self._width + self._height)
# 测试
rect = Rectangle(10, 5)
print(f"宽度: {rect.width}, 高度: {rect.height}") # 宽度: 10, 高度: 5
print(f"面积: {rect.area}") # 面积: 50
print(f"周长: {rect.perimeter}") # 周长: 30
rect.width = 20
rect.height = 8
print(f"新面积: {rect.area}") # 新面积: 160
3.3 只读属性与计算属性
class Circle:
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
return self._radius
@property
def diameter(self):
"""计算属性:直径"""
return 2 * self._radius
@property
def area(self):
"""计算属性:面积"""
return 3.14159 * self._radius ** 2
@property
def circumference(self):
"""计算属性:周长"""
return 2 * 3.14159 * self._radius
# 测试
circle = Circle(5)
print(f"半径: {circle.radius}") # 半径: 5
print(f"直径: {circle.diameter}") # 直径: 10
print(f"面积: {circle.area:.2f}") # 面积: 78.54
print(f"周长: {circle.circumference:.2f}") # 周长: 31.42
四、继承
4.1 单继承
# 父类(基类)
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
return f"{self.name} is eating."
def sleep(self):
return f"{self.name} is sleeping."
def make_sound(self):
return "Some generic animal sound"
# 子类(派生类)
class Dog(Animal):
def __init__(self, name, age, breed):
# 调用父类的构造方法
super().__init__(name, age)
self.breed = breed
def make_sound(self):
"""重写父类方法"""
return "Woof! Woof!"
def fetch(self):
"""子类特有的方法"""
return f"{self.name} is fetching the ball."
class Cat(Animal):
def __init__(self, name, age, color):
super().__init__(name, age)
self.color = color
def make_sound(self):
"""重写父类方法"""
return "Meow!"
def climb(self):
"""子类特有的方法"""
return f"{self.name} is climbing a tree."
# 测试
dog = Dog("Buddy", 3, "Golden Retriever")
cat = Cat("Whiskers", 2, "White")
print(dog.eat()) # Buddy is eating.
print(dog.make_sound()) # Woof! Woof!
print(dog.fetch()) # Buddy is fetching the ball.
print(cat.sleep()) # Whiskers is sleeping.
print(cat.make_sound()) # Meow!
print(cat.climb()) # Whiskers is climbing a tree.
4.2 多继承
- 多个父类:一个子类可以继承多个父类
- 方法解析顺序 (MRO):决定方法的搜索顺序
class Engine:
def __init__(self, horsepower):
self.horsepower = horsepower
def start(self):
return "Engine started"
def stop(self):
return "Engine stopped"
class ElectricSystem:
def __init__(self, battery_capacity):
self.battery_capacity = battery_capacity
def charge(self):
return "Charging electric system"
def check_battery(self):
return f"Battery: {self.battery_capacity} kWh"
class HybridCar(Engine, ElectricSystem):
def __init__(self, horsepower, battery_capacity, model):
# 分别初始化两个父类
Engine.__init__(self, horsepower)
ElectricSystem.__init__(self, battery_capacity)
self.model = model
def drive(self):
return f"{self.model} is driving with {self.horsepower} HP"
def hybrid_mode(self):
return "Switching to hybrid mode"
# 测试
car = HybridCar(150, 20, "Prius")
print(car.start()) # Engine started
print(car.charge()) # Charging electric system
print(car.check_battery()) # Battery: 20 kWh
print(car.drive()) # Prius is driving with 150 HP
# 查看MRO
print(HybridCar.__mro__)
4.3 方法重写
- 完全重写:重新实现父类方法
- 扩展重写:调用父类方法,添加额外功能
class Vehicle:
def __init__(self, brand, model):
self.brand = brand
self.model = model
def start(self):
return f"{self.brand} {self.model} is starting"
def get_info(self):
return f"Vehicle: {self.brand} {self.model}"
class ElectricCar(Vehicle):
def __init__(self, brand, model, battery_capacity):
super().__init__(brand, model)
self.battery_capacity = battery_capacity
def start(self):
"""完全重写"""
return f"{self.brand} {self.model} (Electric) is starting silently"
def get_info(self):
"""扩展重写"""
base_info = super().get_info()
return f"{base_info}, Battery: {self.battery_capacity}kWh"
# 测试
car = ElectricCar("Tesla", "Model 3", 75)
print(car.start()) # Tesla Model 3 (Electric) is starting silently
print(car.get_info()) # Vehicle: Tesla Model 3, Battery: 75kWh
4.4 抽象基类
- 定义接口:规定子类必须实现的方法
abc模块:提供抽象基类支持@abstractmethod:抽象方法装饰器
from abc import ABC, abstractmethod
# 抽象基类
class Shape(ABC):
@abstractmethod
def area(self):
"""计算面积(抽象方法)"""
pass
@abstractmethod
def perimeter(self):
"""计算周长(抽象方法)"""
pass
def describe(self):
"""具体方法"""
return f"This is a {self.__class__.__name__}"
# 具体子类
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):
"""实现抽象方法"""
return 3.14159 * self.radius ** 2
def perimeter(self):
"""实现抽象方法"""
return 2 * 3.14159 * self.radius
# 测试
shapes = [Rectangle(10, 5), Circle(7)]
for shape in shapes:
print(shape.describe())
print(f"面积: {shape.area():.2f}")
print(f"周长: {shape.perimeter():.2f}")
print("-" * 30)
五、多态
5.1 多态概念
- 定义:同一操作作用于不同的对象,可以有不同的解释
- 实现方式:继承 + 方法重写
- 优点:提高代码的灵活性和可扩展性
class Animal:
def make_sound(self):
return "Some animal sound"
class Dog(Animal):
def make_sound(self):
return "Woof!"
class Cat(Animal):
def make_sound(self):
return "Meow!"
class Duck(Animal):
def make_sound(self):
return "Quack!"
# 多态示例
animals = [Dog(), Cat(), Duck(), Animal()]
for animal in animals:
print(animal.make_sound())
# 输出:
# Woof!
# Meow!
# Quack!
# Some animal sound
5.2 鸭子类型
- “如果它走起路来像鸭子,叫起来也像鸭子,那么它就是鸭子”
- 不关心对象类型,只关心对象的行为
- Python 动态类型的优势
# 不需要继承同一个父类
class Dog:
def make_sound(self):
return "Woof!"
class Car:
def make_sound(self):
return "Vroom!"
class Person:
def make_sound(self):
return "Hello!"
# 鸭子类型:只要对象有 make_sound 方法
def make_it_talk(obj):
return obj.make_sound()
# 测试
objects = [Dog(), Car(), Person()]
for obj in objects:
print(make_it_talk(obj))
# 输出:
# Woof!
# Vroom!
# Hello!
5.3 运算符重载
- 特殊方法:以双下划线开头和结尾
- 自定义对象行为:使对象支持内置运算
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
"""str() 函数调用"""
return f"Vector({self.x}, {self.y})"
def __repr__(self):
"""repr() 函数调用,用于调试"""
return f"Vector({self.x}, {self.y})"
def __add__(self, other):
"""+ 运算符重载"""
if isinstance(other, Vector):
return Vector(self.x + other.x, self.y + other.y)
raise TypeError("只能与 Vector 相加")
def __sub__(self, other):
"""- 运算符重载"""
if isinstance(other, Vector):
return Vector(self.x - other.x, self.y - other.y)
raise TypeError("只能与 Vector 相减")
def __mul__(self, scalar):
"""* 运算符重载(向量与标量相乘)"""
if isinstance(scalar, (int, float)):
return Vector(self.x * scalar, self.y * scalar)
raise TypeError("只能与标量相乘")
def __eq__(self, other):
"""== 运算符重载"""
if isinstance(other, Vector):
return self.x == other.x and self.y == other.y
return False
def __len__(self):
"""len() 函数调用,返回维度"""
return 2
def __getitem__(self, index):
"""[] 索引访问"""
if index == 0:
return self.x
elif index == 1:
return self.y
raise IndexError("Vector 索引超出范围")
# 测试
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(v1) # Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(v1 - v2) # Vector(2, 2)
print(v1 * 2) # Vector(6, 8)
print(v1 == Vector(3, 4)) # True
print(len(v1)) # 2
print(v1[0], v1[1]) # 3 4
六、特殊方法与魔法方法
6.1 对象创建与销毁
class Resource:
def __new__(cls, *args, **kwargs):
"""创建实例时调用,在 __init__ 之前"""
print("__new__ 被调用")
instance = super().__new__(cls)
return instance
def __init__(self, name):
"""初始化实例"""
print("__init__ 被调用")
self.name = name
self.is_open = False
def __del__(self):
"""对象被销毁时调用"""
print(f"__del__ 被调用: {self.name}")
def open(self):
self.is_open = True
print(f"Resource {self.name} opened")
def close(self):
self.is_open = False
print(f"Resource {self.name} closed")
# 测试
res = Resource("文件1")
res.open()
res.close()
# 程序结束或对象被垃圾回收时,__del__ 被调用
6.2 字符串表示
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
"""用户友好的字符串表示,str() 和 print() 调用"""
return f"Person: {self.name}, {self.age} years old"
def __repr__(self):
"""开发者友好的字符串表示,用于调试,repr() 调用"""
return f"Person('{self.name}', {self.age})"
def __format__(self, format_spec):
"""format() 函数调用"""
if format_spec == "short":
return f"{self.name[:3]}... ({self.age})"
elif format_spec == "long":
return f"{self.name} is {self.age} years old"
else:
return str(self)
# 测试
person = Person("Alice", 30)
print(str(person)) # Person: Alice, 30 years old
print(repr(person)) # Person('Alice', 30)
print(f"{person}") # Person: Alice, 30 years old
print(f"{person:short}") # Ali... (30)
print(f"{person:long}") # Alice is 30 years old
6.3 比较运算符
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __eq__(self, other):
"""== 运算符"""
if isinstance(other, Student):
return self.score == other.score
return False
def __ne__(self, other):
"""!= 运算符"""
return not self.__eq__(other)
def __lt__(self, other):
"""< 运算符"""
if isinstance(other, Student):
return self.score < other.score
raise TypeError("不能比较不同类型")
def __le__(self, other):
"""<= 运算符"""
if isinstance(other, Student):
return self.score <= other.score
raise TypeError("不能比较不同类型")
def __gt__(self, other):
"""> 运算符"""
if isinstance(other, Student):
return self.score > other.score
raise TypeError("不能比较不同类型")
def __ge__(self, other):
""">= 运算符"""
if isinstance(other, Student):
return self.score >= other.score
raise TypeError("不能比较不同类型")
# 测试
s1 = Student("Alice", 90)
s2 = Student("Bob", 85)
s3 = Student("Charlie", 90)
print(s1 == s2) # False
print(s1 == s3) # True
print(s1 != s2) # True
print(s1 < s2) # False
print(s1 > s2) # True
print(s1 <= s3) # True
print(s1 >= s3) # True
6.4 数值运算
class Fraction:
"""分数类"""
def __init__(self, numerator, denominator=1):
if denominator == 0:
raise ValueError("分母不能为0")
self.numerator = numerator
self.denominator = denominator
self._simplify()
def _simplify(self):
"""约分"""
import math
gcd = math.gcd(self.numerator, self.denominator)
self.numerator //= gcd
self.denominator //= gcd
def __str__(self):
return f"{self.numerator}/{self.denominator}"
def __repr__(self):
return f"Fraction({self.numerator}, {self.denominator})"
def __add__(self, other):
if isinstance(other, Fraction):
new_num = (self.numerator * other.denominator +
other.numerator * self.denominator)
new_den = self.denominator * other.denominator
return Fraction(new_num, new_den)
raise TypeError("只能与 Fraction 相加")
def __sub__(self, other):
if isinstance(other, Fraction):
new_num = (self.numerator * other.denominator -
other.numerator * self.denominator)
new_den = self.denominator * other.denominator
return Fraction(new_num, new_den)
raise TypeError("只能与 Fraction 相减")
def __mul__(self, other):
if isinstance(other, Fraction):
new_num = self.numerator * other.numerator
new_den = self.denominator * other.denominator
return Fraction(new_num, new_den)
raise TypeError("只能与 Fraction 相乘")
def __truediv__(self, other):
if isinstance(other, Fraction):
new_num = self.numerator * other.denominator
new_den = self.denominator * other.numerator
return Fraction(new_num, new_den)
raise TypeError("只能与 Fraction 相除")
def __float__(self):
"""转换为浮点数"""
return self.numerator / self.denominator
def __int__(self):
"""转换为整数(向下取整)"""
return self.numerator // self.denominator
# 测试
f1 = Fraction(1, 2)
f2 = Fraction(1, 3)
print(f1 + f2) # 5/6
print(f1 - f2) # 1/6
print(f1 * f2) # 1/6
print(f1 / f2) # 3/2
print(float(f1)) # 0.5
print(int(f1)) # 0
6.5 容器类型模拟
class Playlist:
"""播放列表,模拟列表行为"""
def __init__(self, *songs):
self.songs = list(songs)
def __len__(self):
"""返回歌曲数量"""
return len(self.songs)
def __getitem__(self, index):
"""索引访问"""
return self.songs[index]
def __setitem__(self, index, value):
"""设置索引处的值"""
self.songs[index] = value
def __delitem__(self, index):
"""删除索引处的值"""
del self.songs[index]
def __contains__(self, item):
"""in 运算符"""
return item in self.songs
def __iter__(self):
"""迭代器"""
return iter(self.songs)
def __reversed__(self):
"""reversed() 函数"""
return reversed(self.songs)
def append(self, song):
self.songs.append(song)
def __str__(self):
return "\n".join(f"{i+1}. {song}" for i, song in enumerate(self.songs))
# 测试
playlist = Playlist("Song1", "Song2", "Song3")
playlist.append("Song4")
print(f"播放列表长度: {len(playlist)}") # 4
print(f"第一首歌: {playlist[0]}") # Song1
print(f"包含 Song2: {'Song2' in playlist}") # True
playlist[1] = "New Song"
print("\n修改后的播放列表:")
print(playlist)
print("\n反向迭代:")
for song in reversed(playlist):
print(song)
七、类装饰器与元类
7.1 类装饰器
def add_method(cls):
"""类装饰器:为类添加新方法"""
def hello(self):
return f"Hello from {self.__class__.__name__}"
def goodbye(self):
return f"Goodbye from {self.__class__.__name__}"
# 动态添加方法
cls.hello = hello
cls.goodbye = goodbye
return cls
def add_attribute(name, value):
"""带参数的类装饰器:为类添加属性"""
def decorator(cls):
setattr(cls, name, value)
return cls
return decorator
@add_method
@add_attribute("version", "1.0")
class MyClass:
def __init__(self, name):
self.name = name
# 测试
obj = MyClass("Test")
print(obj.hello()) # Hello from MyClass
print(obj.goodbye()) # Goodbye from MyClass
print(MyClass.version) # 1.0
7.2 属性装饰器高级用法
class CachedProperty:
"""属性装饰器:缓存计算结果"""
def __init__(self, func):
self.func = func
self.cache_name = f"_cache_{func.__name__}"
def __get__(self, obj, objtype=None):
if obj is None:
return self
if not hasattr(obj, self.cache_name):
value = self.func(obj)
setattr(obj, self.cache_name, value)
return getattr(obj, self.cache_name)
class DataProcessor:
def __init__(self, data):
self.data = data
@CachedProperty
def processed_data(self):
"""耗时计算,结果会被缓存"""
print("Processing data...")
# 模拟耗时计算
result = [x * 2 for x in self.data]
return result
# 测试
processor = DataProcessor([1, 2, 3, 4, 5])
print(processor.processed_data) # Processing data... 然后输出 [2, 4, 6, 8, 10]
print(processor.processed_data) # 直接输出 [2, 4, 6, 8, 10],不再计算
7.3 描述符
- 控制属性访问:
__get__,__set__,__delete__ - 应用场景:类型检查、数据验证、惰性计算
class TypedAttribute:
"""类型检查描述符"""
def __init__(self, name, expected_type):
self.name = name
self.expected_type = expected_type
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj.__dict__.get(self.name)
def __set__(self, obj, value):
if not isinstance(value, self.expected_type):
raise TypeError(f"{self.name} 必须是 {self.expected_type.__name__} 类型")
obj.__dict__[self.name] = value
def __delete__(self, obj):
del obj.__dict__[self.name]
class PositiveNumber:
"""正数描述符"""
def __init__(self, name):
self.name = name
def __get__(self, obj, objtype=None):
if obj is None:
return self
return obj.__dict__.get(self.name)
def __set__(self, obj, value):
if not isinstance(value, (int, float)):
raise TypeError(f"{self.name} 必须是数字")
if value <= 0:
raise ValueError(f"{self.name} 必须是正数")
obj.__dict__[self.name] = value
class Person:
# 使用描述符
name = TypedAttribute("name", str)
age = TypedAttribute("age", int)
salary = PositiveNumber("salary")
def __init__(self, name, age, salary):
self.name = name
self.age = age
self.salary = salary
# 测试
person = Person("Alice", 30, 50000)
print(person.name, person.age, person.salary) # Alice 30 50000
try:
person.name = 123 # TypeError: name 必须是 str 类型
except TypeError as e:
print(f"错误: {e}")
try:
person.salary = -1000 # ValueError: salary 必须是正数
except ValueError as e:
print(f"错误: {e}")
7.4 元类
- 类的类:控制类的创建行为
type:所有类的元类__metaclass__:指定元类
class SingletonMeta(type):
"""单例元类"""
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
instance = super().__call__(*args, **kwargs)
cls._instances[cls] = instance
return cls._instances[cls]
class Logger(metaclass=SingletonMeta):
"""单例类:日志记录器"""
def __init__(self, name="Default"):
self.name = name
self.logs = []
def log(self, message):
self.logs.append(message)
def show_logs(self):
for log in self.logs:
print(f"[{self.name}] {log}")
# 测试
logger1 = Logger("App")
logger2 = Logger("Another") # 这个名称会被忽略
logger1.log("第一条日志")
logger2.log("第二条日志")
print(logger1 is logger2) # True
logger1.show_logs()
# 输出:
# [App] 第一条日志
# [App] 第二条日志
八、设计模式
8.1 工厂模式
from enum import Enum
class VehicleType(Enum):
CAR = "car"
TRUCK = "truck"
MOTORCYCLE = "motorcycle"
class Vehicle:
def drive(self):
pass
class Car(Vehicle):
def drive(self):
return "Driving a car"
class Truck(Vehicle):
def drive(self):
return "Driving a truck"
class Motorcycle(Vehicle):
def drive(self):
return "Riding a motorcycle"
class VehicleFactory:
"""工厂类"""
@staticmethod
def create_vehicle(vehicle_type):
if vehicle_type == VehicleType.CAR:
return Car()
elif vehicle_type == VehicleType.TRUCK:
return Truck()
elif vehicle_type == VehicleType.MOTORCYCLE:
return Motorcycle()
else:
raise ValueError(f"未知的车辆类型: {vehicle_type}")
# 使用工厂
car = VehicleFactory.create_vehicle(VehicleType.CAR)
truck = VehicleFactory.create_vehicle(VehicleType.TRUCK)
print(car.drive()) # Driving a car
print(truck.drive()) # Driving a truck
8.2 观察者模式
class Observer:
"""观察者接口"""
def update(self, message):
pass
class Subject:
"""主题(被观察者)"""
def __init__(self):
self._observers = []
def attach(self, observer):
"""添加观察者"""
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer):
"""移除观察者"""
self._observers.remove(observer)
def notify(self, message):
"""通知所有观察者"""
for observer in self._observers:
observer.update(message)
class EmailNotifier(Observer):
"""邮件通知器"""
def update(self, message):
print(f"发送邮件: {message}")
class SMSNotifier(Observer):
"""短信通知器"""
def update(self, message):
print(f"发送短信: {message}")
class AppNotifier(Observer):
"""应用通知器"""
def update(self, message):
print(f"应用通知: {message}")
# 测试
weather_station = Subject()
email_notifier = EmailNotifier()
sms_notifier = SMSNotifier()
app_notifier = AppNotifier()
weather_station.attach(email_notifier)
weather_station.attach(sms_notifier)
weather_station.attach(app_notifier)
weather_station.notify("温度: 25°C")
# 输出:
# 发送邮件: 温度: 25°C
# 发送短信: 温度: 25°C
# 应用通知: 温度: 25°C
weather_station.detach(sms_notifier)
weather_station.notify("湿度: 60%")
# 输出:
# 发送邮件: 湿度: 60%
# 应用通知: 湿度: 60%
8.3 策略模式
from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
"""支付策略接口"""
@abstractmethod
def pay(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
"""信用卡支付"""
def __init__(self, card_number, cvv):
self.card_number = card_number
self.cvv = cvv
def pay(self, amount):
return f"信用卡支付 {amount} 元,卡号: {self.card_number[-4:]}"
class PayPalPayment(PaymentStrategy):
"""PayPal支付"""
def __init__(self, email):
self.email = email
def pay(self, amount):
return f"PayPal支付 {amount} 元,邮箱: {self.email}"
class BitcoinPayment(PaymentStrategy):
"""比特币支付"""
def __init__(self, wallet_address):
self.wallet_address = wallet_address
def pay(self, amount):
return f"比特币支付 {amount} 元,钱包地址: {self.wallet_address[:8]}..."
class ShoppingCart:
"""购物车"""
def __init__(self):
self.items = []
self.payment_strategy = None
def add_item(self, item, price):
self.items.append((item, price))
def set_payment_strategy(self, strategy):
self.payment_strategy = strategy
def checkout(self):
if not self.payment_strategy:
raise ValueError("未设置支付方式")
total = sum(price for _, price in self.items)
return self.payment_strategy.pay(total)
# 测试
cart = ShoppingCart()
cart.add_item("笔记本电脑", 7999)
cart.add_item("鼠标", 199)
# 使用信用卡支付
cart.set_payment_strategy(CreditCardPayment("1234-5678-9012-3456", "123"))
print(cart.checkout()) # 信用卡支付 8198 元,卡号: 3456
# 切换支付方式
cart.set_payment_strategy(PayPalPayment("user@example.com"))
print(cart.checkout()) # PayPal支付 8198 元,邮箱: user@example.com
8.4 装饰器模式
class Coffee:
"""咖啡接口"""
def get_cost(self):
pass
def get_description(self):
pass
class SimpleCoffee(Coffee):
"""简单咖啡"""
def get_cost(self):
return 5
def get_description(self):
return "Simple coffee"
class CoffeeDecorator(Coffee):
"""咖啡装饰器基类"""
def __init__(self, coffee):
self._coffee = coffee
def get_cost(self):
return self._coffee.get_cost()
def get_description(self):
return self._coffee.get_description()
class MilkDecorator(CoffeeDecorator):
"""牛奶装饰器"""
def get_cost(self):
return self._coffee.get_cost() + 2
def get_description(self):
return self._coffee.get_description() + ", milk"
class SugarDecorator(CoffeeDecorator):
"""糖装饰器"""
def get_cost(self):
return self._coffee.get_cost() + 1
def get_description(self):
return self._coffee.get_description() + ", sugar"
class WhippedCreamDecorator(CoffeeDecorator):
"""奶油装饰器"""
def get_cost(self):
return self._coffee.get_cost() + 3
def get_description(self):
return self._coffee.get_description() + ", whipped cream"
# 测试
coffee = SimpleCoffee()
print(f"{coffee.get_description()}: ${coffee.get_cost()}") # Simple coffee: $5
# 加牛奶
coffee_with_milk = MilkDecorator(coffee)
print(f"{coffee_with_milk.get_description()}: ${coffee_with_milk.get_cost()}") # Simple coffee, milk: $7
# 加牛奶和糖
coffee_with_milk_sugar = SugarDecorator(coffee_with_milk)
print(f"{coffee_with_milk_sugar.get_description()}: ${coffee_with_milk_sugar.get_cost()}") # Simple coffee, milk, sugar: $8
# 加牛奶、糖和奶油
coffee_deluxe = WhippedCreamDecorator(coffee_with_milk_sugar)
print(f"{coffee_deluxe.get_description()}: ${coffee_deluxe.get_cost()}") # Simple coffee, milk, sugar, whipped cream: $11
九、高级主题
9.1 混入类
- 多重继承的特殊用法
- 提供特定功能,不用于创建实例
class JSONMixin:
"""JSON混入类"""
def to_json(self):
import json
return json.dumps(self.__dict__, indent=2)
@classmethod
def from_json(cls, json_str):
import json
data = json.loads(json_str)
return cls(**data)
class XMLMixin:
"""XML混入类"""
def to_xml(self):
import xml.etree.ElementTree as ET
root = ET.Element(self.__class__.__name__)
for key, value in self.__dict__.items():
child = ET.SubElement(root, key)
child.text = str(value)
return ET.tostring(root, encoding='unicode')
class LoggableMixin:
"""日志混入类"""
def log(self, message):
print(f"[{self.__class__.__name__}] {message}")
class Person(JSONMixin, XMLMixin, LoggableMixin):
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
# 测试
person = Person("Alice", 30, "New York")
person.log("对象已创建") # [Person] 对象已创建
json_str = person.to_json()
print("JSON格式:")
print(json_str)
xml_str = person.to_xml()
print("\nXML格式:")
print(xml_str)
# 从JSON恢复对象
person2 = Person.from_json(json_str)
print(f"\n恢复的对象: {person2.name}, {person2.age}, {person2.city}")
9.2 数据类
- Python 3.7+ 新增特性
- 简化类的创建,自动生成特殊方法
from dataclasses import dataclass, field, asdict, astuple
from typing import List, ClassVar
from datetime import datetime
@dataclass(order=True, frozen=False)
class Product:
"""数据类:产品"""
# 实例属性
name: str
price: float
tags: List[str] = field(default_factory=list)
created_at: datetime = field(default_factory=datetime.now)
# 类属性
currency: ClassVar[str] = "USD"
def get_price_with_currency(self):
return f"{self.currency} {self.price:.2f}"
# 测试
product1 = Product("Laptop", 999.99, ["electronics", "computers"])
product2 = Product("Mouse", 29.99, ["electronics", "accessories"])
product3 = Product("Laptop", 999.99, ["electronics", "computers"])
print(product1) # Product(name='Laptop', price=999.99, tags=['electronics', 'computers'], ...)
print(product1 == product3) # True
print(product1.get_price_with_currency()) # USD 999.99
# 转换为字典
print(asdict(product1))
# 转换为元组
print(astuple(product1))
# 排序(因为设置了 order=True)
products = [product2, product1]
print(sorted(products)) # 按名称和价格排序
9.3 枚举类
from enum import Enum, IntEnum, auto, unique
@unique
class Color(Enum):
"""颜色枚举"""
RED = 1
GREEN = 2
BLUE = 3
YELLOW = 4
class Status(IntEnum):
"""状态枚举(整数枚举)"""
PENDING = auto() # 1
PROCESSING = auto() # 2
COMPLETED = auto() # 3
FAILED = auto() # 4
class Direction(Enum):
"""方向枚举(带值)"""
NORTH = (0, 1)
SOUTH = (0, -1)
EAST = (1, 0)
WEST = (-1, 0)
def __init__(self, dx, dy):
self.dx = dx
self.dy = dy
def move(self, x, y, distance=1):
return x + self.dx * distance, y + self.dy * distance
# 测试
color = Color.RED
print(color) # Color.RED
print(color.name) # RED
print(color.value) # 1
print(list(Color)) # [<Color.RED: 1>, <Color.GREEN: 2>, ...]
status = Status.PROCESSING
print(status) # Status.PROCESSING
print(status.value) # 2
direction = Direction.NORTH
x, y = 0, 0
new_x, new_y = direction.move(x, y, 5)
print(f"从({x},{y})向{direction.name}移动5个单位: ({new_x},{new_y})") # (0,5)
9.4 命名元组
from collections import namedtuple
from typing import NamedTuple
# 方式1: collections.namedtuple
Point = namedtuple('Point', ['x', 'y'])
p1 = Point(10, 20)
print(p1.x, p1.y) # 10 20
print(p1[0], p1[1]) # 10 20
# 方式2: typing.NamedTuple(支持类型注解)
class Employee(NamedTuple):
name: str
age: int
department: str = "Engineering"
def get_info(self):
return f"{self.name}, {self.age}, {self.department}"
emp = Employee("Alice", 30)
print(emp) # Employee(name='Alice', age=30, department='Engineering')
print(emp.get_info()) # Alice, 30, Engineering
print(emp._asdict()) # {'name': 'Alice', 'age': 30, 'department': 'Engineering'}
# 创建新实例,修改部分字段
emp_new = emp._replace(age=31, department="Sales")
print(emp_new) # Employee(name='Alice', age=31, department='Sales')
9.5 抽象基类高级用法
from abc import ABC, abstractmethod, abstractproperty
from collections.abc import Sequence, Sized
class CustomList(Sequence, Sized):
"""自定义列表,实现Sequence和Sized接口"""
def __init__(self, *args):
self._data = list(args)
def __getitem__(self, index):
return self._data[index]
def __len__(self):
return len(self._data)
def __str__(self):
return str(self._data)
# 测试
my_list = CustomList(1, 2, 3, 4, 5)
print(my_list) # [1, 2, 3, 4, 5]
print(len(my_list)) # 5
print(my_list[2]) # 3
print(3 in my_list) # True
print(list(my_list)) # [1, 2, 3, 4, 5]
# 检查是否实现了接口
print(isinstance(my_list, Sequence)) # True
print(isinstance(my_list, Sized)) # True
十、最佳实践
10.1 类设计原则
- 组合优于继承:尽量使用组合而不是继承
- 接口隔离:定义小而专一的接口
- 依赖抽象:依赖接口而不是具体实现
- 最少知识原则:减少对象之间的耦合
- 单一职责:一个类只做一件事
10.2 代码组织
- 模块化:将相关类放在同一模块
- 包结构:使用包组织相关模块
- 导入规范:避免循环导入
- 文档字符串:为类和方法添加文档
- 类型注解:使用类型提示提高代码可读性
10.3 性能考虑
__slots__:减少内存使用- 属性缓存:缓存计算结果
- 惰性加载:延迟初始化
- 对象池:复用对象减少创建开销
class OptimizedClass:
"""使用__slots__优化内存"""
__slots__ = ['x', 'y', 'z'] # 固定属性列表
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __str__(self):
return f"({self.x}, {self.y}, {self.z})"
# 测试
obj = OptimizedClass(1, 2, 3)
print(obj) # (1, 2, 3)
# obj.new_attr = 4 # 错误:不能添加新属性
10.4 测试策略
- 单元测试:测试单个类和方法
- 集成测试:测试类之间的协作
- Mock对象:模拟依赖对象
- 测试夹具:重用测试数据
- 覆盖率:确保代码覆盖
10.5 调试技巧
__repr__:提供详细的调试信息- 日志记录:记录对象状态变化
- 断言:验证对象状态
- 调试器:使用pdb进行交互式调试
- 属性检查:验证对象完整性
十一、学习资源
11.1 官方文档
- Python官方文档:类和对象相关章节
- PEP文档:PEP 3119(抽象基类)、PEP 557(数据类)等
- 标准库文档:abc、collections、dataclasses等模块
11.2 推荐书籍
- 《Python高级编程》:面向对象高级特性
- 《流畅的Python》:深入讲解Python面向对象
- 《设计模式:可复用面向对象软件的基础》:经典设计模式
- 《Python Cookbook》:实用编程技巧
11.3 在线资源
- Real Python:面向对象编程教程
- Python官方教程:类和对象基础
- Stack Overflow:问题解答
- GitHub:开源项目代码学习
11.4 练习项目
- 游戏开发:角色、道具、场景类设计
- Web框架:模拟Flask/Django的MVC结构
- GUI应用:使用面向对象设计界面
- 数据处理:设计数据管道和处理类
- 网络爬虫:设计爬虫框架和组件
11.5 进阶方向
- 元编程:深入理解Python对象模型
- 设计模式:掌握更多设计模式
- 架构设计:大型系统面向对象设计
- 并发编程:面向对象与并发结合
- 函数式编程:与面向对象结合使用