1. 类的基本概念解析
在Python中,类(Class)是面向对象编程(OOP)的核心概念。简单来说,类就是一个创建对象的蓝图或模板。就像建筑图纸决定了房子的结构和功能一样,类定义了对象将拥有的属性和行为。
我第一次真正理解类的威力是在开发一个电商系统时。当时需要处理成千上万的商品数据,每个商品都有名称、价格、库存等属性,还需要计算折扣、更新库存等方法。如果不用类,代码会变得极其混乱。通过创建Product类,所有相关数据和操作都被整洁地封装在一起。
关键理解:类不仅是数据的容器,更重要的是它将数据和对数据的操作绑定在一起,这是面向对象与面向过程编程的本质区别。
2. 类的组成要素详解
2.1 类的定义语法
Python中使用class关键字定义类,基本语法如下:
python复制class ClassName:
"""类的文档字符串"""
class_attribute = value # 类属性
def __init__(self, param1, param2):
self.instance_attribute1 = param1 # 实例属性
self.instance_attribute2 = param2
def instance_method(self):
"""实例方法"""
return self.instance_attribute1
这里有几个关键点需要注意:
- 类名通常采用大驼峰命名法(ClassName)
__init__是特殊的实例化方法(构造函数)- 所有实例方法的第一个参数都是
self,代表实例本身
2.2 类属性 vs 实例属性
初学者最容易混淆的概念就是类属性和实例属性的区别:
python复制class Dog:
species = "Canis familiaris" # 类属性
def __init__(self, name, age):
self.name = name # 实例属性
self.age = age
- 类属性:所有实例共享,通过类名或实例访问
- 实例属性:每个实例独有,只能通过实例访问
实际经验:类属性适合存储类级别的常量或默认值,而实例属性存储对象特有的状态。
3. 类的方法类型
3.1 实例方法
最常见的类型,必须包含self参数,用于访问和修改实例状态:
python复制class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
3.2 类方法
使用@classmethod装饰器定义,第一个参数是cls(类本身),常用于替代构造函数:
python复制class Pizza:
def __init__(self, ingredients):
self.ingredients = ingredients
@classmethod
def margherita(cls):
return cls(["mozzarella", "tomatoes"])
@classmethod
def prosciutto(cls):
return cls(["mozzarella", "tomatoes", "ham"])
3.3 静态方法
使用@staticmethod装饰器,不需要self或cls参数,相当于放在类中的普通函数:
python复制class MathUtils:
@staticmethod
def add(a, b):
return a + b
选择建议:能用静态方法就不用类方法,除非需要访问或修改类状态。
4. 类的继承与多态
4.1 基本继承语法
继承是OOP的三大特性之一(封装、继承、多态),Python中使用简单:
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!"
4.2 方法重写与super()
子类可以重写父类方法,使用super()调用父类实现:
python复制class Parent:
def __init__(self, name):
self.name = name
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # 调用父类__init__
self.age = age
4.3 多重继承与MRO
Python支持多重继承,方法解析顺序(MRO)决定方法查找路径:
python复制class A:
def method(self):
print("A method")
class B(A):
def method(self):
print("B method")
class C(A):
def method(self):
print("C method")
class D(B, C):
pass
d = D()
d.method() # 输出"B method"
print(D.mro()) # 显示方法解析顺序
经验之谈:多重继承虽然强大但容易导致"菱形继承"问题,建议优先使用组合而非继承。
5. 特殊方法与运算符重载
Python通过特殊方法(双下划线方法)实现运算符重载等高级特性:
5.1 常用特殊方法
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
5.2 属性访问控制
通过@property装饰器实现属性访问控制:
python复制class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("温度不能低于绝对零度")
self._celsius = value
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
6. 类的实际应用案例
6.1 数据库模型类
python复制class User:
def __init__(self, username, email):
self.username = username
self.email = email
self._password = None
@property
def password(self):
raise AttributeError("密码不可读")
@password.setter
def password(self, plaintext):
import hashlib
self._password = hashlib.sha256(plaintext.encode()).hexdigest()
def check_password(self, plaintext):
import hashlib
return self._password == hashlib.sha256(plaintext.encode()).hexdigest()
6.2 游戏开发中的类设计
python复制class Character:
def __init__(self, name, health, attack_power):
self.name = name
self.health = health
self.attack_power = attack_power
def attack(self, target):
target.health -= self.attack_power
print(f"{self.name}攻击了{target.name},造成{self.attack_power}点伤害")
def is_alive(self):
return self.health > 0
class Player(Character):
def __init__(self, name, health, attack_power, level=1):
super().__init__(name, health, attack_power)
self.level = level
def level_up(self):
self.level += 1
self.health += 10
self.attack_power += 5
print(f"{self.name}升级到{self.level}级!")
7. 类的高级特性
7.1 抽象基类(ABC)
使用abc模块定义抽象基类:
python复制from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def area(self):
pass
@abstractmethod
def perimeter(self):
pass
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14 * self.radius ** 2
def perimeter(self):
return 2 * 3.14 * self.radius
7.2 类装饰器
类也可以作为装饰器使用:
python复制def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class DatabaseConnection:
def __init__(self):
print("创建数据库连接")
7.3 数据类(Python 3.7+)
使用@dataclass简化类定义:
python复制from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
z: float = 0.0 # 默认值
def distance(self) -> float:
return (self.x**2 + self.y**2 + self.z**2) ** 0.5
8. 类设计的最佳实践
- 单一职责原则:一个类应该只有一个引起它变化的原因
- 开放封闭原则:对扩展开放,对修改封闭
- 组合优于继承:优先使用组合而非继承来复用代码
- 小类原则:保持类的小巧和专注
- 高内聚低耦合:类内部高度相关,类之间尽量减少依赖
我在实际项目中最常犯的错误是创建了"上帝类"——试图做太多事情的超大类。后来通过以下方法改进:
- 将大类拆分为多个小类
- 使用组合代替继承
- 遵循"告诉而非询问"原则
- 使用依赖注入减少耦合
9. 常见问题与解决方案
9.1 何时使用类 vs 函数?
-
使用类的情况:
- 需要维护状态(属性)
- 需要组合数据和操作
- 需要创建多个相似对象
- 需要继承或多态
-
使用函数的情况:
- 操作是无状态的
- 逻辑简单独立
- 不需要面向对象特性
9.2 如何选择继承与组合?
继承(is-a关系)示例:
python复制class Employee(Person): # 员工是一个人
pass
组合(has-a关系)示例:
python复制class Employee:
def __init__(self, person, employee_id):
self.person = person # 员工有一个人
self.employee_id = employee_id
经验法则:如果关系更像是"有一个"而非"是一个",则使用组合。
9.3 Python中的私有成员
Python没有真正的私有成员,但约定:
- 单下划线
_var:提示"这是内部实现,不要直接访问" - 双下划线
__var:名称修饰(Name Mangling),会变成_ClassName__var
python复制class Test:
def __init__(self):
self.public = 1
self._protected = 2
self.__private = 3
10. 性能考虑与优化
10.1 __slots__优化内存
对于创建大量实例的类,使用__slots__可以显著减少内存占用:
python复制class Point:
__slots__ = ['x', 'y'] # 固定属性列表
def __init__(self, x, y):
self.x = x
self.y = y
原理:阻止创建__dict__,固定内存布局
10.2 避免在__init__中执行复杂操作
__init__应该只做必要的初始化,延迟加载耗时资源:
python复制class LazyLoader:
def __init__(self):
self._data = None
@property
def data(self):
if self._data is None:
self._load_data()
return self._data
def _load_data(self):
# 模拟耗时操作
import time
time.sleep(2)
self._data = "加载的数据"
10.3 使用弱引用避免内存泄漏
循环引用可能导致内存无法回收,使用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)
11. 测试与调试技巧
11.1 单元测试类
使用unittest测试类:
python复制import unittest
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
11.2 使用pdb调试
在类方法中设置断点:
python复制import pdb
class ComplexCalculation:
def calculate(self, x):
result = 0
pdb.set_trace() # 在这里暂停
for i in range(x):
result += i**2
return result
11.3 使用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}")
# 执行查询...
12. 类与元类
12.1 理解元类
元类是创建类的"类",默认是type:
python复制class Meta(type):
def __new__(cls, name, bases, namespace):
print(f"创建类 {name}")
return super().__new__(cls, name, bases, namespace)
class MyClass(metaclass=Meta):
pass
12.2 元类的实际应用
实现自动注册所有子类:
python复制class PluginMeta(type):
plugins = []
def __init__(cls, name, bases, namespace):
super().__init__(name, bases, namespace)
if not name.startswith('Base'):
PluginMeta.plugins.append(cls)
class BasePlugin(metaclass=PluginMeta):
pass
class Plugin1(BasePlugin):
pass
class Plugin2(BasePlugin):
pass
print(PluginMeta.plugins) # 输出[<class '__main__.Plugin1'>, <class '__main__.Plugin2'>]
13. 设计模式中的类
13.1 工厂模式
python复制class Button:
def render(self):
pass
class WindowsButton(Button):
def render(self):
return "Windows风格按钮"
class MacOSButton(Button):
def render(self):
return "MacOS风格按钮"
def create_button(os_type):
if os_type == "windows":
return WindowsButton()
elif os_type == "mac":
return MacOSButton()
else:
raise ValueError("未知操作系统类型")
13.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)
14. Python类的发展趋势
14.1 类型注解支持
Python 3.5+支持类型注解,使类定义更清晰:
python复制from typing import List, Optional
class TreeNode:
def __init__(self, value: int, children: Optional[List['TreeNode']] = None):
self.value = value
self.children = children or []
def add_child(self, node: 'TreeNode') -> None:
self.children.append(node)
14.2 数据类与属性装饰器
Python 3.7+的数据类和属性装饰器简化了类定义:
python复制from dataclasses import dataclass
from typing import ClassVar
@dataclass
class InventoryItem:
name: str
unit_price: float
quantity: int = 0
discount: ClassVar[float] = 0.1
def total_cost(self) -> float:
return self.unit_price * self.quantity * (1 - self.discount)
15. 类与并发编程
15.1 线程安全类
使用锁保证线程安全:
python复制import threading
class Counter:
def __init__(self):
self._value = 0
self._lock = threading.Lock()
def increment(self):
with self._lock:
self._value += 1
def value(self):
with self._lock:
return self._value
15.2 异步类
使用async/await定义异步方法:
python复制import aiohttp
class AsyncFetcher:
async def fetch(self, url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
16. 类与序列化
16.1 实现__dict__和__getstate__
控制pickle序列化行为:
python复制import pickle
class StatefulClass:
def __init__(self, value):
self.value = value
self._internal = "secret"
def __getstate__(self):
state = self.__dict__.copy()
del state['_internal'] # 不序列化内部属性
return state
def __setstate__(self, state):
self.__dict__.update(state)
self._internal = "restored" # 恢复默认值
obj = StatefulClass(42)
serialized = pickle.dumps(obj)
restored = pickle.loads(serialized)
16.2 使用dataclasses和asdict
python复制from dataclasses import dataclass, asdict
@dataclass
class Point:
x: int
y: int
p = Point(10, 20)
print(asdict(p)) # 输出{'x': 10, 'y': 20}
17. 类与描述符协议
17.1 属性描述符
实现__get__, __set__, __delete__方法:
python复制class PositiveNumber:
def __init__(self, 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('radius')
def __init__(self, radius):
self.radius = radius
17.2 延迟加载描述符
python复制class LazyProperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
if instance is None:
return self
value = self.func(instance)
instance.__dict__[self.func.__name__] = value
return value
class MyClass:
@LazyProperty
def expensive_computation(self):
print("执行耗时计算...")
return 42
18. 类与上下文管理
18.1 实现上下文协议
通过__enter__和__exit__方法:
python复制class DatabaseConnection:
def __enter__(self):
self.connect()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.disconnect()
if exc_type is not None:
print(f"发生错误: {exc_val}")
return False # 不抑制异常
# 使用方式
with DatabaseConnection() as db:
db.query("SELECT * FROM users")
18.2 使用contextlib简化
python复制from contextlib import contextmanager
@contextmanager
def temporary_file():
import tempfile
f = tempfile.NamedTemporaryFile(delete=False)
try:
yield f
finally:
import os
os.unlink(f.name)
19. 类与装饰器交互
19.1 类作为装饰器
python复制class TraceCalls:
def __init__(self, func):
self.func = func
self.call_count = 0
def __call__(self, *args, **kwargs):
self.call_count += 1
print(f"调用 {self.func.__name__} (第{self.call_count}次)")
return self.func(*args, **kwargs)
@TraceCalls
def say_hello(name):
print(f"Hello, {name}!")
19.2 装饰类方法
python复制def log_method_call(func):
def wrapper(*args, **kwargs):
print(f"调用方法 {func.__name__}")
return func(*args, **kwargs)
return wrapper
class Calculator:
@log_method_call
def add(self, a, b):
return a + b
20. 类与元编程
20.1 动态创建类
使用type()动态创建类:
python复制def init(self, name):
self.name = name
def say_hello(self):
print(f"Hello, {self.name}!")
Person = type('Person', (), {
'__init__': init,
'say_hello': say_hello
})
p = Person("Alice")
p.say_hello()
20.2 修改类行为
通过修改类的__dict__:
python复制class Original:
pass
def new_method(self):
return 42
Original.new_method = new_method
obj = Original()
print(obj.new_method()) # 输出42
21. 类与性能分析
21.1 使用timeit测试方法性能
python复制import timeit
class TestClass:
def method_to_test(self):
return sum(i*i for i in range(1000))
t = TestClass()
time = timeit.timeit(t.method_to_test, number=1000)
print(f"平均执行时间: {time/1000:.6f}秒")
21.2 使用cProfile分析类
python复制import cProfile
class ComplexCalculation:
def calculate(self):
total = 0
for i in range(10000):
for j in range(100):
total += i * j
return total
profiler = cProfile.Profile()
profiler.enable()
calc = ComplexCalculation()
calc.calculate()
profiler.disable()
profiler.print_stats(sort='time')
22. 类与文档化
22.1 文档字符串规范
python复制class DocumentedClass:
"""这是一个示例类的文档字符串
这里可以详细描述类的用途、功能和注意事项。
Attributes:
attr1 (int): 第一个属性的描述
attr2 (str): 第二个属性的描述
"""
def __init__(self, param1, param2):
"""初始化方法
Args:
param1 (int): 第一个参数的描述
param2 (str): 第二个参数的描述
"""
self.attr1 = param1
self.attr2 = param2
def example_method(self, arg1):
"""示例方法的文档字符串
Args:
arg1 (float): 参数的描述
Returns:
bool: 返回值的描述
"""
return bool(arg1 > 0)
22.2 使用Sphinx生成文档
在docstring中使用reStructuredText格式:
python复制class MathUtils:
"""数学工具类
提供各种数学计算功能
:ivar pi: 圆周率常量
:vartype pi: float
"""
pi = 3.1415926
def circle_area(self, radius):
"""计算圆的面积
:param radius: 圆的半径
:type radius: float
:return: 圆的面积
:rtype: float
:raises ValueError: 如果半径为负
"""
if radius < 0:
raise ValueError("半径不能为负")
return self.pi * radius ** 2
23. 类与测试驱动开发(TDD)
23.1 先写测试再实现类
python复制import unittest
# 先写测试
class TestStringCalculator(unittest.TestCase):
def test_add_empty_string(self):
calc = StringCalculator()
self.assertEqual(calc.add(""), 0)
def test_add_single_number(self):
calc = StringCalculator()
self.assertEqual(calc.add("5"), 5)
def test_add_two_numbers(self):
calc = StringCalculator()
self.assertEqual(calc.add("3,5"), 8)
# 然后实现类
class StringCalculator:
def add(self, numbers):
if not numbers:
return 0
return sum(int(num) for num in numbers.split(','))
23.2 使用mock测试类交互
python复制from unittest.mock import Mock
class TestPaymentProcessor(unittest.TestCase):
def test_process_payment(self):
# 创建mock对象
payment_gateway = Mock()
payment_gateway.charge.return_value = True
processor = PaymentProcessor(payment_gateway)
result = processor.process_payment(100, "4111111111111111")
self.assertTrue(result)
payment_gateway.charge.assert_called_once_with(100, "4111111111111111")
class PaymentProcessor:
def __init__(self, payment_gateway):
self.payment_gateway = payment_gateway
def process_payment(self, amount, card_number):
return self.payment_gateway.charge(amount, card_number)
24. 类与设计原则
24.1 SOLID原则应用
- 单一职责原则(SRP):
python复制# 违反SRP
class User:
def __init__(self, name):
self.name = name
def save(self):
# 保存到数据库
def send_email(self, message):
# 发送邮件
# 遵循SRP
class User:
def __init__(self, name):
self.name = name
class UserRepository:
def save(self, user):
# 保存到数据库
class EmailService:
def send_email(self, user, message):
# 发送邮件
- 开闭原则(OCP):
python复制class Shape:
def area(self):
pass
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):
return 3.14 * self.radius ** 2
def total_area(shapes):
return sum(shape.area() for shape in shapes)
24.2 依赖倒置原则(DIP)
python复制# 高层模块不应该依赖低层模块,两者都应该依赖抽象
class Database(ABC):
@abstractmethod
def save(self, data):
pass
class MySQLDatabase(Database):
def save(self, data):
print(f"将数据保存到MySQL: {data}")
class UserService:
def __init__(self, database):
self.database = database
def create_user(self, user_data):
self.database.save(user_data)
25. 类与函数式编程结合
25.1 不可变类
使用@dataclass(frozen=True)创建不可变类:
python复制from dataclasses import dataclass
@dataclass(frozen=True)
class ImmutablePoint:
x: float
y: float
p = ImmutablePoint(1.0, 2.0)
# p.x = 3.0 # 会引发dataclasses.FrozenInstanceError
25.2 高阶方法与函数组合
python复制from functools import reduce
class NumberList:
def __init__(self, numbers):
self.numbers = numbers
def filter(self, predicate):
return NumberList(list(filter(predicate, self.numbers)))
def map(self, func):
return NumberList(list(map(func, self.numbers)))
def reduce(self, func, initial):
return reduce(func, self.numbers, initial)
nums = NumberList([1, 2, 3, 4, 5])
result = nums.filter(lambda x: x % 2 == 0).map(lambda x: x * 2).reduce(lambda a, b: a + b, 0)
print(result) # 输出12 (2*2 + 4*2)
26. 类与并发模式
26.1 使用asyncio实现异步类
python复制import asyncio
class AsyncCounter:
def __init__(self):
self._value = 0
self._lock = asyncio.Lock()
async def increment(self):
async with self._lock:
self._value += 1
async def get_value(self):
async with self._lock:
return self._value
26.2 使用线程池的类
python复制from concurrent.futures import ThreadPoolExecutor
class ParallelProcessor:
def __init__(self, max_workers=4):
self.executor = ThreadPoolExecutor(max_workers=max_workers)
def process_task(self, task_func, *args):
return self.executor.submit(task_func, *args)
def shutdown(self):
self.executor.shutdown()
27. 类与性能优化技巧
27.1 使用__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 # 会引发AttributeError
27.2 延迟计算属性
python复制class LazyProperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
if instance is None:
return self
value = self.func(instance)
instance.__dict__[self.func.__name__] = value
return value
class Circle:
def __init__(self, radius):
self.radius = radius
@LazyProperty
def area(self):
print("计算面积...")
return 3.14 * self.radius ** 2
28. 类与设计模式深入
28.1 策略模式
python复制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 PaymentContext:
def __init__(self, strategy):
self.strategy = strategy
def execute_payment(self, amount):
self.strategy.pay(amount)
28.2 装饰器模式
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()
coffee_with_milk_and_sugar = Sugar(Milk(coffee))
print(coffee_with_milk_and_sugar.cost()) # 输出8
29. 类与元编程高级技巧
29.1 动态添加方法
python复制import types
class MyClass:
pass
def new_method(self):
return "动态添加的方法"
obj = MyClass()
obj.dynamic_method = types.MethodType(new_method, obj)
print(obj.dynamic_method()) # 输出"动态添加的方法"
29.2 类工厂函数
python复制def class_factory(class_name, **attributes):
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
cls_attrs = {'__init__': __init__}
cls_attrs.update(attributes)
return type(class_name, (), cls_attrs)
Dog = class_factory('Dog', bark=lambda self: "Woof!")
d = Dog()
print(d.bark()) # 输出"Woof!"
30. 类与Python内部机制
30.1 方法解析顺序(MRO)
python复制class A:
def method(self):
print("A method")
class B(A):
def method(self):
print("B method")
class C(A):
def method(self):
print("C method")
class D(B, C):
pass
print(D.mro()) # 输出[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
d = D()
d.method() # 输出"B method"
30.2 描述符协议深入
python复制class RevealAccess:
def __init__(self, initval=None, name='var'):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print(f"获取 {self.name}")
return self.val
def __set__(self, obj, val):
print(f"设置 {self.name} 为 {val}")
self.val = val
class MyClass:
x = RevealAccess(10, 'var "x"')
y = 5
m = MyClass()
print(m.x) # 输出"获取 var "x"" 然后输出10
m.x = 20 # 输出"设置 var "x" 为 20"
print(m.y) # 直接输出5,不触发描述符
31. 类与Python数据模型
31.1 实现容器协议
python复制class CustomList:
def __init__(self, *args):
self._data = list(args)
def __len__(self):
return len(self._data)
def __getitem__(self, index):
return self._data[index]
def __setitem__(self, index, value):
self._data[index] = value
def __delitem__(self, index):
del self._data[index]
def __iter__(self):
return iter(self._data)
def __contains__(self, item):
return item in self._data
def append(self, item):
self._data.append(item)
def __repr__(self):
return f"CustomList({self._data})