__sizeof__没有被sys.getsizeof调用

4
我正在使用Python编写一个动态数组实现(类似于内置的列表类),需要观察容量的增长(每次达到极限时会加倍)。为此,我有以下代码,但输出很奇怪。看起来sys.getsizeof()从不调用我的类的__sizeof__()。为了测试,我让__sizeof__()返回0,但根据sys.getsizeof()它是非零的。
问题出在哪里?
import ctypes

class DynamicArray(object):
    '''
    DYNAMIC ARRAY CLASS (Similar to Python List)
    '''

    def __init__(self):
        self.n = 0 # Count actual elements (Default is 0)
        self.capacity = 1 # Default Capacity
        self.A = self.make_array(self.capacity)

    def __len__(self):
        """
        Return number of elements sorted in array
        """
        return self.n

    def __getitem__(self,k):
        """
        Return element at index k
        """
        if not 0 <= k <self.n:
            return IndexError('K is out of bounds!') # Check it k index is in bounds of array

        return self.A[k] #Retrieve from array at index k

    def append(self, ele):
        """
        Add element to end of the array
        """
        if self.n == self.capacity:
            self._resize(2*self.capacity) #Double capacity if not enough room

        self.A[self.n] = ele #Set self.n index to element
        self.n += 1

    def _resize(self,new_cap):
        """
        Resize internal array to capacity new_cap
        """
        print("resize called!")

        B = self.make_array(new_cap) # New bigger array

        for k in range(self.n): # Reference all existing values
            B[k] = self.A[k]

        self.A = B # Call A the new bigger array
        self.capacity = new_cap # Reset the capacity

    def make_array(self,new_cap):
        """
        Returns a new array with new_cap capacity
        """
        return (new_cap * ctypes.py_object)()

    def __sizeof__(self):
        return 0

测试大小调整的代码:
arr2 = DynamicArray()

import sys

for i in range(100):
    print(len(arr2), " ", sys.getsizeof(arr2))
    arr2.append(i)

输出结果如下:

0   24
1   24
resize called!
2   24
resize called!
3   24
4   24
resize called!
5   24
6   24
7   24
8   24
resize called!
9   24
10   24
11   24
12   24
13   24
14   24
15   24
16   24
resize called!
17   24
18   24
19   24
20   24
21   24
22   24
23   24
24   24
25   24
26   24
27   24
28   24
29   24
30   24
31   24
32   24
resize called!
33   24
34   24
35   24
36   24
37   24
38   24
39   24
40   24
41   24
42   24
43   24
44   24
45   24
46   24
47   24
48   24
49   24
50   24
51   24
52   24
53   24
54   24
55   24
56   24
57   24
58   24
59   24
60   24
61   24
62   24
63   24
64   24
resize called!
65   24
66   24
67   24
68   24
69   24
70   24
71   24
72   24
73   24
74   24
75   24
76   24
77   24
78   24
79   24
80   24
81   24
82   24
83   24
84   24
85   24
86   24
87   24
88   24
89   24
90   24
91   24
92   24
93   24
94   24
95   24
96   24
97   24
98   24
99   24
1个回答

6

你的__sizeof__正在被调用,只是它添加了垃圾收集器开销,这就是为什么结果不为零的原因。

有关sys.getsizeof的文档:

getsizeof()调用对象的__sizeof__方法,并在对象由垃圾收集器管理时添加额外的垃圾收集器开销。

返回0是使自己难以理解它被调用的一种方式,因为你总是会得到相同的结果(0+开销)。

根据动态数组的内容返回一个大小,以便看到它的变化。


进一步解释:

在CPython中,每个对象都有一些附加的管理信息,存储在一个PyGC_head结构中,该结构被添加进去

/* add gc_head size */
if (PyObject_IS_GC(o))
    return ((size_t)size) + sizeof(PyGC_Head);
return (size_t)size;

这是垃圾回收器使用的。

为什么它会增加总体大小,可能是因为它确实代表了对象所需的额外内存。在Python层面上,您不需要担心垃圾的收集并将其视为魔法,但是,在请求对象大小信息时,您不应该为了保持幻觉而牺牲正确的结果。


4
让你的__sizeof __()返回一个非零值,你会发现观察到的值增加了这个数量。 - Leon
@Leon 没错,我刚刚把那个加到答案里了 :-) - Dimitris Fasarakis Hilliard
垃圾回收器“开销”?我完全不确定我理解了什么。什么开销?为什么应该将开销添加为整数?难道垃圾回收不应该是自动的、隐式的、神奇的、不干扰的等等吗? :) - ankush981
@dotslash我在我的回答中添加了一点内容,希望它能解决你的进一步疑虑。 - Dimitris Fasarakis Hilliard
1
是的,这很有帮助。感谢您的努力。我现在认为我应该复习一下C语言,并深入研究Python源代码。 - ankush981
@Leon @Dimitris Fasarakis Hilliard 为什么 sys.getsizeof() 在默认实现下会返回0?它不应该调用像 sizeof() 这样的 C 函数来计算大小吗? - Cherrymelon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接