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 教程。