1. 类的基本概念与定义方式
在面向对象编程中,类(Class)是最基础的代码组织单元。它就像是一个蓝图或者模具,定义了对象(Object)应该具有的属性和行为。我们先来看一个最简单的类定义示例:
python复制class Person:
pass
这个空类虽然什么都不做,但已经具备了类的基本结构。class是定义类的关键字,Person是类名,按照Python的命名规范,类名应该采用大驼峰命名法(每个单词首字母大写)。
1.1 类的组成要素
一个完整的类通常包含以下几个部分:
- 类名:标识类的名称,如上面的
Person - 属性:描述类的特征(变量)
- 方法:定义类的行为(函数)
- 构造函数:
__init__方法,用于初始化对象
让我们扩展上面的Person类:
python复制class Person:
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age # 实例属性
def greet(self): # 实例方法
return f"Hello, my name is {self.name} and I'm {self.age} years old."
1.2 类与实例的关系
类定义完成后,我们可以创建该类的实例(对象):
python复制person1 = Person("Alice", 30)
person2 = Person("Bob", 25)
print(person1.greet()) # 输出: Hello, my name is Alice and I'm 30 years old.
print(person2.greet()) # 输出: Hello, my name is Bob and I'm 25 years old.
每个实例都是独立的,修改一个实例的属性不会影响其他实例:
python复制person1.age = 31
print(person1.greet()) # Alice的年龄变为31
print(person2.greet()) # Bob的年龄仍为25
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 类的核心特性详解
2.1 构造函数__init__
__init__方法是Python类的构造函数,在创建实例时自动调用。它的第一个参数必须是self,表示实例本身。通过self我们可以访问和设置实例的属性。
注意:虽然第一个参数名为
self是约定俗成的,但你可以使用其他名称。不过强烈建议遵循惯例使用self,否则代码会难以理解。
2.2 实例方法与self参数
类中定义的普通方法(如上面的greet)都是实例方法,它们的第一个参数也必须是self。通过self,方法可以访问该实例的所有属性和其他方法。
调用实例方法时,Python会自动将实例作为self参数传入,所以我们只需要提供其他参数:
python复制# 正确调用方式
person1.greet()
# 技术上等价但不要这样写
Person.greet(person1)
2.3 类属性与实例属性
类属性是属于类本身的属性,所有实例共享;实例属性是属于特定实例的属性:
python复制class Dog:
species = "Canis familiaris" # 类属性,所有狗共享
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age # 实例属性
dog1 = Dog("Buddy", 5)
dog2 = Dog("Milo", 3)
print(dog1.species) # Canis familiaris
print(dog2.species) # Canis familiaris
# 修改类属性会影响所有实例
Dog.species = "Canis lupus"
print(dog1.species) # Canis lupus
print(dog2.species) # Canis lupus
# 通过实例修改类属性会创建同名实例属性
dog1.species = "Canis aureus"
print(dog1.species) # Canis aureus (实例属性)
print(dog2.species) # Canis lupus (仍访问类属性)
3. 类的高级特性
3.1 类方法与静态方法
除了实例方法,类还可以定义类方法和静态方法:
python复制class MyClass:
class_attribute = "类属性"
@classmethod
def class_method(cls):
print(f"这是一个类方法,可以访问{cls.class_attribute}")
return cls
@staticmethod
def static_method():
print("这是一个静态方法,与类和实例都无关")
- 类方法:使用
@classmethod装饰器,第一个参数是cls(类本身),可以访问类属性 - 静态方法:使用
@staticmethod装饰器,不需要self或cls参数,与普通函数类似
3.2 属性装饰器@property
@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("半径必须是正数")
self._radius = value
@property
def area(self):
"""计算圆的面积"""
return 3.14159 * self._radius ** 2
circle = Circle(5)
print(circle.radius) # 5
print(circle.area) # 78.53975
circle.radius = 10
print(circle.area) # 314.159
try:
circle.radius = -1 # 触发ValueError
except ValueError as e:
print(e) # 半径必须是正数
3.3 特殊方法(魔术方法)
Python类可以通过实现特殊方法(以双下划线开头和结尾)来定义特殊行为:
python复制class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
"""定义+操作"""
return Vector(self.x + other.x, self.y + other.y)
def __str__(self):
"""定义打印时的字符串表示"""
return f"Vector({self.x}, {self.y})"
def __len__(self):
"""定义len()函数的行为"""
return 2 # 二维向量
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(len(v1)) # 2
常见的特殊方法包括:
__init__: 构造函数__str__: 字符串表示__repr__: 官方字符串表示__len__: 定义长度__getitem__,__setitem__: 索引操作__add__,__sub__等: 运算符重载
4. 类的继承与多态
4.1 基本继承
继承是面向对象的重要特性,允许子类继承父类的属性和方法:
python复制class Animal:
def __init__(self, name):
self.name = name
def speak(self):
raise NotImplementedError("子类必须实现此方法")
class Dog(Animal):
def speak(self):
return f"{self.name} says Woof!"
class Cat(Animal):
def speak(self):
return f"{self.name} says Meow!"
animals = [Dog("Buddy"), Cat("Whiskers")]
for animal in animals:
print(animal.speak())
# 输出:
# Buddy says Woof!
# Whiskers says Meow!
4.2 方法重写与super()
子类可以重写父类的方法,如果需要调用父类的方法,可以使用super():
python复制class Parent:
def __init__(self, name):
self.name = name
print("Parent初始化")
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # 调用父类的__init__
self.age = age
print("Child初始化")
child = Child("Alice", 10)
# 输出:
# Parent初始化
# Child初始化
4.3 多重继承与方法解析顺序(MRO)
Python支持多重继承,方法解析顺序(MRO)决定了方法的查找顺序:
python复制class A:
def method(self):
print("A的方法")
class B(A):
def method(self):
print("B的方法")
class C(A):
def method(self):
print("C的方法")
class D(B, C):
pass
d = D()
d.method() # 输出: B的方法
print(D.mro()) # 显示方法解析顺序: [D, B, C, A, object]
可以使用类名.mro()查看方法解析顺序。当出现"菱形继承"问题时,Python使用C3线性化算法确定MRO。
5. 类的设计原则与最佳实践
5.1 SOLID原则
- 单一职责原则(SRP): 一个类只负责一项职责
- 开闭原则(OCP): 对扩展开放,对修改关闭
- 里氏替换原则(LSP): 子类应该可以替换父类而不影响程序正确性
- 接口隔离原则(ISP): 客户端不应被迫依赖它不使用的接口
- 依赖倒置原则(DIP): 高层模块不应依赖低层模块,都应依赖抽象
5.2 组合优于继承
当需要复用代码时,优先考虑组合(将类作为属性)而不是继承:
python复制class Engine:
def start(self):
print("引擎启动")
class Car:
def __init__(self):
self.engine = Engine() # 组合
def start(self):
self.engine.start()
print("汽车启动")
car = Car()
car.start()
5.3 封装与信息隐藏
使用单下划线_表示"受保护"的属性,双下划线__表示"私有"属性:
python复制class BankAccount:
def __init__(self, balance):
self.__balance = balance # 私有属性
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def get_balance(self):
return self.__balance
account = BankAccount(1000)
# account.__balance # 报错,无法直接访问
print(account.get_balance()) # 1000
注意:Python中的"私有"只是名称改写(Name Mangling),实际上仍可通过
_类名__属性名访问,但这是一种约定,应该避免直接访问。
5.4 抽象基类(ABC)
使用abc模块定义抽象基类,强制子类实现特定方法:
python复制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)
# shape = Shape() # 报错,不能实例化抽象类
rect = Rectangle(3, 4)
print(rect.area()) # 12
6. 常见问题与解决方案
6.1 类变量与实例变量混淆
python复制class MyClass:
items = [] # 类变量
def add_item(self, item):
self.items.append(item)
a = MyClass()
b = MyClass()
a.add_item(1)
b.add_item(2)
print(a.items) # [1, 2] 因为items是类变量,被所有实例共享
解决方案:在__init__中初始化实例变量:
python复制class MyClass:
def __init__(self):
self.items = [] # 实例变量
6.2 可变默认参数
python复制class MyClass:
def __init__(self, items=[]): # 可变默认参数
self.items = items
def add_item(self, item):
self.items.append(item)
a = MyClass()
b = MyClass()
a.add_item(1)
b.add_item(2)
print(a.items) # [1, 2] 因为默认参数在定义时创建,被所有实例共享
解决方案:使用None作为默认值:
python复制class MyClass:
def __init__(self, items=None):
self.items = items if items is not None else []
6.3 方法绑定问题
python复制class MyClass:
def method(self):
print("实例方法")
obj = MyClass()
method = obj.method # 绑定方法
method() # 正常调用
unbound_method = MyClass.method # 未绑定方法
# unbound_method() # 报错,缺少self参数
unbound_method(obj) # 需要显式传递实例
6.4 属性访问控制
python复制class Person:
def __init__(self, name):
self._name = name # 受保护属性
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError("名字必须是字符串")
self._name = value
p = Person("Alice")
print(p.name) # Alice
p.name = "Bob"
# p.name = 123 # 触发TypeError
7. 实际应用案例
7.1 实现一个简单的银行账户系统
python复制class BankAccount:
def __init__(self, account_holder, initial_balance=0):
self.account_holder = account_holder
self._balance = initial_balance
self._transactions = []
@property
def balance(self):
return self._balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("存款金额必须为正数")
self._balance += amount
self._transactions.append(("存款", amount))
return self._balance
def withdraw(self, amount):
if amount <= 0:
raise ValueError("取款金额必须为正数")
if amount > self._balance:
raise ValueError("余额不足")
self._balance -= amount
self._transactions.append(("取款", amount))
return self._balance
def get_transactions(self):
return self._transactions.copy() # 返回副本防止外部修改
account = BankAccount("张三", 1000)
account.deposit(500)
account.withdraw(200)
print(account.balance) # 1300
print(account.get_transactions()) # [('存款', 500), ('取款', 200)]
7.2 实现一个图形界面中的按钮类
python复制class Button:
def __init__(self, text, width=100, height=30):
self.text = text
self.width = width
self.height = height
self._click_handlers = []
def on_click(self, handler):
"""注册点击事件处理器"""
self._click_handlers.append(handler)
def click(self):
"""模拟按钮点击"""
print(f"按钮'{self.text}'被点击")
for handler in self._click_handlers:
handler(self)
def render(self):
"""渲染按钮到屏幕"""
print(f"渲染按钮: {self.text} [{self.width}x{self.height}]")
def button_clicked(button):
print(f"处理按钮点击: {button.text}")
btn = Button("提交")
btn.on_click(button_clicked)
btn.render()
btn.click()
7.3 实现一个简单的购物车系统
python复制class Product:
def __init__(self, id, name, price):
self.id = id
self.name = name
self.price = price
def __str__(self):
return f"{self.name} (${self.price:.2f})"
class ShoppingCart:
def __init__(self):
self._items = {} # {product: quantity}
def add_item(self, product, quantity=1):
if quantity <= 0:
raise ValueError("数量必须为正数")
if product in self._items:
self._items[product] += quantity
else:
self._items[product] = quantity
def remove_item(self, product, quantity=1):
if product not in self._items:
raise ValueError("商品不在购物车中")
if quantity <= 0:
raise ValueError("数量必须为正数")
if quantity >= self._items[product]:
del self._items[product]
else:
self._items[product] -= quantity
@property
def total(self):
return sum(product.price * quantity for product, quantity in self._items.items())
def __str__(self):
if not self._items:
return "购物车为空"
items_str = "\n".join(f"{product} x{quantity}"
for product, quantity in self._items.items())
return f"{items_str}\n总计: ${self.total:.2f}"
# 使用示例
apple = Product(1, "苹果", 0.99)
banana = Product(2, "香蕉", 1.29)
cart = ShoppingCart()
cart.add_item(apple, 3)
cart.add_item(banana, 2)
print(cart)
cart.remove_item(apple, 1)
print("\n移除1个苹果后:")
print(cart)
8. 类的高级应用技巧
8.1 使用描述符(Descriptor)控制属性访问
描述符是实现属性访问控制的底层机制,@property实际上是描述符的一种简化形式:
python复制class PositiveNumber:
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
return instance.__dict__[self.name]
def __set__(self, instance, value):
if value <= 0:
raise ValueError("必须是正数")
instance.__dict__[self.name] = value
class Circle:
radius = PositiveNumber() # 描述符
def __init__(self, radius):
self.radius = radius
c = Circle(5)
print(c.radius) # 5
# c.radius = -1 # 触发ValueError
8.2 使用元类(Metaclass)控制类的创建
元类是类的类,可以自定义类的创建过程:
python复制class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Singleton(metaclass=SingletonMeta):
pass
a = Singleton()
b = Singleton()
print(a is b) # True,实现了单例模式
8.3 使用数据类(Data Class)简化类定义
Python 3.7+引入了dataclass装饰器,可以自动生成__init__、__repr__等方法:
python复制from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
z: float = 0.0 # 默认值
p = Point(1.5, 2.5)
print(p) # Point(x=1.5, y=2.5, z=0.0)
8.4 使用枚举类(Enum)定义常量
python复制from enum import Enum, auto
class Color(Enum):
RED = auto()
GREEN = auto()
BLUE = auto()
print(Color.RED) # Color.RED
print(Color.RED.name) # RED
print(Color.RED.value) # 1
8.5 使用类型注解提高代码可读性
Python 3.5+支持类型注解,虽然不影响运行时,但可以提高代码可读性和IDE支持:
python复制from typing import List, Dict, Optional
class Product:
def __init__(self, id: int, name: str, price: float):
self.id = id
self.name = name
self.price = price
class ShoppingCart:
def __init__(self):
self._items: Dict[Product, int] = {}
def add_item(self, product: Product, quantity: int = 1) -> None:
if product in self._items:
self._items[product] += quantity
else:
self._items[product] = quantity
def get_items(self) -> List[tuple[Product, int]]:
return list(self._items.items())
9. 类与Python生态系统
9.1 类在流行框架中的应用
Django模型示例:
python复制from django.db import models
class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
Flask视图类示例:
python复制from flask import Flask, request
from flask.views import MethodView
app = Flask(__name__)
class UserAPI(MethodView):
def get(self, user_id):
# 处理GET请求
return f"获取用户 {user_id}"
def post(self):
# 处理POST请求
data = request.json
return f"创建用户 {data['name']}"
app.add_url_rule('/user/', view_func=UserAPI.as_view('users'))
app.add_url_rule('/user/<int:user_id>', view_func=UserAPI.as_view('user'))
9.2 类与异步编程
Python的async/await语法也可以用于类方法:
python复制import aiohttp
class AsyncFetcher:
def __init__(self):
self.session = aiohttp.ClientSession()
async def fetch(self, url):
async with self.session.get(url) as response:
return await response.text()
async def close(self):
await self.session.close()
# 使用示例
async def main():
fetcher = AsyncFetcher()
try:
content = await fetcher.fetch("https://example.com")
print(content[:100])
finally:
await fetcher.close()
# 在实际应用中需要运行事件循环
9.3 类与类型检查
使用mypy等工具可以进行静态类型检查:
python复制class Calculator:
def add(self, a: int, b: int) -> int:
return a + b
calc = Calculator()
result = calc.add(1, 2) # 通过类型检查
# result = calc.add("1", "2") # 类型检查会报错
10. 性能优化与高级技巧
10.1 使用__slots__节省内存
对于属性固定的类,可以使用__slots__来节省内存:
python复制class Point:
__slots__ = ['x', 'y'] # 只允许这两个属性
def __init__(self, x, y):
self.x = x
self.y = y
p = Point(1, 2)
# p.z = 3 # 报错,因为__slots__限制了属性
注意:使用
__slots__后,实例不再有__dict__属性,无法动态添加新属性。
10.2 使用弱引用(WeakRef)避免循环引用
python复制import weakref
class Node:
def __init__(self, value):
self.value = value
self._parent = None
self.children = []
@property
def parent(self):
return self._parent() if self._parent is not None else None
@parent.setter
def parent(self, node):
self._parent = weakref.ref(node) # 使用弱引用避免循环引用
root = Node("root")
child = Node("child")
child.parent = root
root.children.append(child)
10.3 使用functools.cached_property缓存计算结果
Python 3.8+提供了cached_property装饰器,可以缓存方法的计算结果:
python复制from functools import cached_property
class DataSet:
def __init__(self, data):
self.data = data
@cached_property
def stats(self):
# 复杂计算
print("计算统计数据...")
return {
'mean': sum(self.data) / len(self.data),
'max': max(self.data),
'min': min(self.data)
}
ds = DataSet([1, 2, 3, 4, 5])
print(ds.stats) # 第一次调用会计算
print(ds.stats) # 第二次调用直接返回缓存结果
10.4 使用__new__方法控制实例创建
__new__方法在__init__之前调用,可以控制实例的创建过程:
python复制class Singleton:
_instance = None
def __new__(cls):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
a = Singleton()
b = Singleton()
print(a is b) # True
11. 测试与调试技巧
11.1 为类编写单元测试
使用unittest模块测试类:
python复制import unittest
class Calculator:
def add(self, a, b):
return a + b
def divide(self, a, b):
if b == 0:
raise ValueError("除数不能为零")
return a / b
class TestCalculator(unittest.TestCase):
def setUp(self):
self.calc = Calculator()
def test_add(self):
self.assertEqual(self.calc.add(1, 2), 3)
def test_divide(self):
self.assertEqual(self.calc.divide(6, 3), 2)
with self.assertRaises(ValueError):
self.calc.divide(1, 0)
if __name__ == '__main__':
unittest.main()
11.2 使用pytest进行更简洁的测试
python复制# test_calculator.py
import pytest
def test_add():
calc = Calculator()
assert calc.add(1, 2) == 3
def test_divide():
calc = Calculator()
assert calc.divide(6, 3) == 2
with pytest.raises(ValueError):
calc.divide(1, 0)
11.3 使用__repr__辅助调试
良好的__repr__方法可以帮助调试:
python复制class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f"Point(x={self.x}, y={self.y})"
p = Point(1, 2)
print(p) # 输出: Point(x=1, y=2)
11.4 使用logging记录类行为
python复制import logging
logging.basicConfig(level=logging.INFO)
class Database:
def __init__(self):
self.logger = logging.getLogger(self.__class__.__name__)
def query(self, sql):
self.logger.info(f"执行查询: {sql}")
# 实际查询逻辑
return []
db = Database()
db.query("SELECT * FROM users")
12. 设计模式实践
12.1 工厂模式
python复制class Shape:
def draw(self):
pass
class Circle(Shape):
def draw(self):
print("绘制圆形")
class Square(Shape):
def draw(self):
print("绘制方形")
class ShapeFactory:
@staticmethod
def create_shape(shape_type):
if shape_type == "circle":
return Circle()
elif shape_type == "square":
return Square()
else:
raise ValueError("未知的形状类型")
# 使用工厂创建对象
circle = ShapeFactory.create_shape("circle")
square = ShapeFactory.create_shape("square")
circle.draw() # 绘制圆形
square.draw() # 绘制方形
12.2 观察者模式
python复制class Observer:
def update(self, subject):
pass
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def detach(self, observer):
self._observers.remove(observer)
def notify(self):
for observer in self._observers:
observer.update(self)
class Data(Subject):
def __init__(self, value):
super().__init__()
self._value = value
@property
def value(self):
return self._value
@value.setter
def value(self, value):
self._value = value
self.notify()
class Display(Observer):
def update(self, subject):
print(f"数据已更新: {subject.value}")
data = Data(10)
display = Display()
data.attach(display)
data.value = 20 # 输出: 数据已更新: 20
12.3 策略模式
python复制from abc import ABC, abstractmethod
class PaymentStrategy(ABC):
@abstractmethod
def pay(self, amount):
pass
class CreditCardPayment(PaymentStrategy):
def pay(self, amount):
print(f"使用信用卡支付 {amount} 元")
class AlipayPayment(PaymentStrategy):
def pay(self, amount):
print(f"使用支付宝支付 {amount} 元")
class Order:
def __init__(self, payment_strategy):
self._payment_strategy = payment_strategy
def process_order(self, amount):
self._payment_strategy.pay(amount)
order1 = Order(CreditCardPayment())
order1.process_order(100) # 使用信用卡支付 100 元
order2 = Order(AlipayPayment())
order2.process_order(200) # 使用支付宝支付 200 元
12.4 装饰器模式
python复制class Coffee:
def cost(self):
return 5
class CoffeeDecorator:
def __init__(self, coffee):
self._coffee = coffee
def cost(self):
return self._coffee.cost()
class Milk(CoffeeDecorator):
def cost(self):
return self._coffee.cost() + 2
class Sugar(CoffeeDecorator):
def cost(self):
return self._coffee.cost() + 1
coffee = Coffee()
print(coffee.cost()) # 5
milk_coffee = Milk(coffee)
print(milk_coffee.cost()) # 7
sweet_milk_coffee = Sugar(milk_coffee)
print(sweet_milk_coffee.cost()) # 8
13. 类与Python特殊协议
13.1 上下文管理协议(enter, exit)
python复制class DatabaseConnection:
def __enter__(self):
print("建立数据库连接")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("关闭数据库连接")
if exc_type is not None:
print(f"发生异常: {exc_val}")
return True # 抑制异常
def query(self, sql):
print(f"执行查询: {sql}")
with DatabaseConnection() as db:
db.query("SELECT * FROM users")
# 1/0 # 如果取消注释,异常会被抑制
13.2 迭代器协议(iter, next)
python复制class CountDown:
def __init__(self, start):
self.current = start
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.current < 0:
raise StopIteration
else:
result = self.current
self.current -= 1
return result
for num in CountDown(5):
print(num) # 输出: 5 4 3 2 1 0
13.3 可调用对象协议(call)
python复制class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return self.n + x
add5 = Adder(5)
print(add5(3)) # 8
13.4 容器协议(getitem, setitem, len)
python复制class ShoppingList:
def __init__(self):
self.items = []
def __getitem__(self, index):
return self.items[index]
def __setitem__(self, index, value):
self.items[index] = value
def __len__(self):
return len(self.items)
def add(self, item):
self.items.append(item)
sl = ShoppingList()
sl.add("苹果")
sl.add("香蕉")
print(sl[0]) # 苹果
print(len(sl)) # 2
14. 类与Python内置函数的集成
14.1 使用__bool__定义真值测试
python复制class Stack:
def __init__(self):
self.items = []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def __bool__(self):
return bool(self.items)
s = Stack()
print(bool(s)) # False
s.push(1)
print(bool(s)) # True
14.2 使用__getattr__实现动态属性
python复制class DynamicAttributes:
def __getattr__(self, name):
if name.startswith('attr_'):
# 动态生成属性值
return len(name)
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
dyn = DynamicAttributes()
print(dyn.attr_test) # 8 (因为"attr_test"长度为8)
# print(dyn.other) # 触发AttributeError
14.3 使用__dir__控制dir()输出
python复制class CustomDir:
def __dir__(self):
return ['a', 'b', 'custom_method']
def custom_method(self):
pass
obj = CustomDir()
print(dir(obj)) # ['a', 'b', 'custom_method']
14.4 使用__format__自定义格式化
python复制class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __format__(self, format_spec):
if format_spec == 'r':
return f"({self.y}, {self.x})" # 反转坐标
return f"({self.x}, {self.y})"
p = Point(1, 2)
print(f"{p}") # (1, 2)
print(f"{p:r}") # (2, 1)
15. 类的高级元编程技巧
15.1 动态创建类
python复制def make_class(class_name, **attributes):
return type(class_name, (), attributes)
MyClass = make_class('MyClass', a=1, b=2)
obj = MyClass()
print(obj.a) # 1
print(obj.b) # 2
15.2 使用类装饰器修改类
python复制def add_method(cls):
def new_method(self):
