Python __len__ 方法
最后修改于 2025 年 4 月 8 日
本综合指南将探讨 Python 的 `__len__` 方法,这是一个允许对象定义其长度的特殊方法。我们将涵盖基本用法、序列协议、自定义容器和实际示例。
基本定义
`__len__` 方法返回对象的长度(项目数)。它由内置的 `len()` 函数调用,并应返回一个非负整数。
主要特点:必须为序列和映射类型实现;应高效(O(1) 复杂度);返回整数 ≥ 0。该方法使对象能够与 Python 的内置函数和运算符一起使用。
基本 __len__ 实现
这是一个实现 `__len__` 的简单类,用于演示其基本用法。该方法允许实例与 `len()` 函数一起使用。
class ShoppingCart: def __init__(self): self.items = [] def add_item(self, item): self.items.append(item) def __len__(self): return len(self.items) cart = ShoppingCart() cart.add_item("Apple") cart.add_item("Banana") print(len(cart)) # Output: 2
此示例展示了一个跟踪项目的购物篮类。 `__len__` 方法委托给内部项目列表的长度。当在购物车实例上调用 `len()` 时,Python 会调用 `__len__`。
实现应快速,因为 `len()` 经常用于性能关键的代码。Python 期望 `__len__` 快速返回。
实现固定大小的容器
对于具有预定大小的容器, `__len__` 可以返回固定值。此示例显示了一个始终报告相同长度的固定大小的队列。
class FixedQueue: def __init__(self, size): self.size = size self._items = [None] * size self._pointer = 0 def enqueue(self, item): self._items[self._pointer] = item self._pointer = (self._pointer + 1) % self.size def __len__(self): return self.size queue = FixedQueue(5) queue.enqueue("A") queue.enqueue("B") print(len(queue)) # Always returns 5
这个固定大小的队列维护一个恒定的容量。 `__len__` 方法返回预定大小而不是当前项目数。
当逻辑大小与物理存储大小不同时,此模式很有用。该方法反映了容器的设计而不是其当前状态。
具有惰性求值的自定义集合
对于长度计算开销大的集合, `__len__` 可以实现缓存或惰性求值来优化性能。
class LargeDataset: def __init__(self, data_source): self.data_source = data_source self._length = None def __len__(self): if self._length is None: print("Calculating length...") self._length = sum(1 for _ in self.data_source) return self._length data = LargeDataset(open('large_file.txt')) print(len(data)) # Calculates on first call print(len(data)) # Uses cached value
此类表示一个大型数据集,其中计算长度非常昂贵。 `__len__` 方法在第一次计算后缓存结果。
惰性求值模式对于文件或数据库查询等资源非常宝贵,因为确定长度需要大量的计算或 I/O。
实现位掩码
对于非传统的集合, `__len__` 可以返回逻辑大小而不是物理大小。此示例显示了一个报告活动位的位掩码类。
class Bitmask: def __init__(self, size): self.size = size self.mask = 0 def set_bit(self, position): self.mask |= (1 << position) def __len__(self): return bin(self.mask).count('1') mask = Bitmask(8) mask.set_bit(2) mask.set_bit(5) print(len(mask)) # Returns 2 (bits set)
此位掩码类将设置的位数计为其长度。 `__len__` 方法将掩码转换为二进制并计算“1”字符。
这演示了 `__len__` 如何以特定于域的方式表示逻辑大小。该方法提供了一致的接口,无论内部表示如何。
具有递归长度的树结构
对于递归数据结构, `__len__` 可以实现递归计数。此示例显示了一个计算所有后代的树节点类。
class TreeNode: def __init__(self, value): self.value = value self.children = [] def add_child(self, node): self.children.append(node) def __len__(self): return 1 + sum(len(child) for child in self.children) root = TreeNode("Root") child1 = TreeNode("Child1") child2 = TreeNode("Child2") grandchild = TreeNode("Grandchild") child1.add_child(grandchild) root.add_child(child1) root.add_child(child2) print(len(root)) # Returns 4 (root + 2 children + 1 grandchild)
此树实现计算层次结构中的所有节点。每个节点贡献 1 加上其子节点的长度。递归处理任意深度。
对于非常深的结构,请考虑迭代实现以避免堆栈溢出。该方法为嵌套数据提供直观的大小报告。
最佳实践
- 仅返回整数:该方法必须返回一个整数 ≥ 0
- 确保 O(1) 复杂度: `len()` 应该很快
- 保持一致:长度应与迭代行为匹配
- 记录行为:阐明长度的含义
- 考虑 __bool__:空集合应为假
资料来源
作者
列出所有 Python 教程。