Python __sizeof__ 方法
最后修改于 2025 年 4 月 8 日
本篇全面的指南探讨了 Python 的 __sizeof__
方法,这个特殊方法会返回对象的内存消耗。我们将涵盖基本用法、内置类型、自定义对象和实际示例。
基本定义
__sizeof__
方法返回对象的大小,以字节为单位,由解释器分配。它提供了对内存使用的深入了解,并有助于优化。
主要特征:它由 sys.getsizeof()
自动调用,返回一个整数,并且可以在自定义类中被重写。 该大小包括对象的开销,但不包括引用的对象。
__sizeof__ 的基本用法
以下是如何将 __sizeof__
与内置类型一起使用来测量它们的内存消耗。 这演示了该方法的基本行为。
import sys lst = [1, 2, 3, 4, 5] print(lst.__sizeof__()) # Direct method call print(sys.getsizeof(lst)) # Recommended way using sys empty_list = [] print(empty_list.__sizeof__()) s = "hello" print(s.__sizeof__())
此示例显示了列表和字符串的内存使用情况。空列表仍然具有来自 Python 列表结构的开销。 建议使用 sys.getsizeof()
,因为它处理了边缘情况。
请注意,大小可能因 Python 版本和实现(CPython、PyPy)而异。 这些值代表 Python 级别的内存,不一定是系统级别的内存。
带有 __sizeof__ 的自定义类
在自定义类中实现 __sizeof__
允许测量它们的内存占用。 此示例显示了一个简单的实现。
import sys class Point: def __init__(self, x, y): self.x = x self.y = y def __sizeof__(self): return object.__sizeof__(self) + \ self.x.__sizeof__() + \ self.y.__sizeof__() p = Point(3, 4) print(sys.getsizeof(p))
这个 Point
该实现对所有组件的大小求和。 对于复杂的对象,如果需要,您需要递归计算所有引用对象的大小。
带有 __sizeof__ 的容器类
对于容器对象,__sizeof__
应该考虑容器及其元素。 此示例演示了此模式。
import sys class CustomList: def __init__(self, *args): self.data = list(args) def __sizeof__(self): size = object.__sizeof__(self) size += self.data.__sizeof__() for item in self.data: size += sys.getsizeof(item) return size cl = CustomList(1, "two", 3.0) print(sys.getsizeof(cl))
这个 CustomList
通过对容器开销、内部列表大小和每个元素的大小求和来计算其总大小。 这提供了完整的内存图片。
为了进行准确的测量,我们在每个元素上使用 sys.getsizeof()
。 这考虑了 Python 在每个包含项目上的对象开销。
带有 Slots 的 __sizeof__
使用 __slots__
的类具有不同的内存特性。 此示例展示了如何为这样的类实现 __sizeof__
。
import sys class SlotPoint: __slots__ = ['x', 'y'] def __init__(self, x, y): self.x = x self.y = y def __sizeof__(self): return object.__sizeof__(self) + \ sys.getsizeof(self.x) + \ sys.getsizeof(self.y) sp = SlotPoint(3, 4) print(sys.getsizeof(sp))
SlotPoint
类使用 __slots__
来提高内存效率。 它的 __sizeof__
实现与常规类相似,但具有不同的基本开销。
基于 Slots 的类通常比常规类消耗更少的内存,因为它们没有用于动态属性的 __dict__
。 这会影响大小计算。
递归 __sizeof__ 实现
对于复杂的嵌套结构,递归的 __sizeof__
实现可以计算包括引用对象在内的总内存使用量。
import sys class TreeNode: def __init__(self, value, left=None, right=None): self.value = value self.left = left self.right = right def __sizeof__(self): size = object.__sizeof__(self) size += sys.getsizeof(self.value) if self.left: size += sys.getsizeof(self.left) if self.right: size += sys.getsizeof(self.right) return size left = TreeNode(1) right = TreeNode(3) root = TreeNode(2, left, right) print(sys.getsizeof(root))
这个 TreeNode
类代表一个二叉树。 它的 __sizeof__
方法递归地在其计算中包括子节点的大小。
对于非常深的结构,这种方法可能效率低下。 在这种情况下,请考虑使用迭代方法或记忆化来优化计算。
最佳实践
- 使用 sys.getsizeof():优先于直接调用 __sizeof__
- 包括所有属性:考虑所有对象组件
- 小心处理递归:避免循环引用的无限循环
- 记录假设:阐明大小中包含的内容
- 与替代方案比较:用于优化决策
资料来源
作者
列出所有 Python 教程。