ZetCode

Python __sizeof__ 方法

最后修改于 2025 年 4 月 8 日

本篇全面的指南探讨了 Python 的 __sizeof__ 方法,这个特殊方法会返回对象的内存消耗。我们将涵盖基本用法、内置类型、自定义对象和实际示例。

基本定义

__sizeof__ 方法返回对象的大小,以字节为单位,由解释器分配。它提供了对内存使用的深入了解,并有助于优化。

主要特征:它由 sys.getsizeof() 自动调用,返回一个整数,并且可以在自定义类中被重写。 该大小包括对象的开销,但不包括引用的对象。

__sizeof__ 的基本用法

以下是如何将 __sizeof__ 与内置类型一起使用来测量它们的内存消耗。 这演示了该方法的基本行为。

basic_sizeof.py
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__ 允许测量它们的内存占用。 此示例显示了一个简单的实现。

custom_sizeof.py
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__ 应该考虑容器及其元素。 此示例演示了此模式。

container_sizeof.py
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__

slots_sizeof.py
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__ 实现可以计算包括引用对象在内的总内存使用量。

recursive_sizeof.py
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__ 方法递归地在其计算中包括子节点的大小。

对于非常深的结构,这种方法可能效率低下。 在这种情况下,请考虑使用迭代方法或记忆化来优化计算。

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程