__sizeof__没有被sys.getsizeof调用 [英] __sizeof__ not getting called by sys.getsizeof

查看:105
本文介绍了__sizeof__没有被sys.getsizeof调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在用Python(类似于内置列表类)编写一个动态数组实现,为此我需要观察容量的增长(每次达到极限时都会翻倍)。为此,我有以下代码,但是输出很奇怪。看来 sys.getsizeof()从未调用我班的 __ sizeof __()。为了进行测试,我将 __ sizeof __()返回 0 ,但按照 sys.getsizeof()它不是零。



有什么收获?

  import ctypes 

class DynamicArray(object):
'''
动态数组类(类似于Python列表)
'''

def __init __(self):
self.n = 0#计算实际元素(默认为0)
self .capacity = 1#默认容量
self.A = self.make_array(self.capacity)

def __len __(self):

返回数字数组中排序的元素

返回self.n

def __getitem __(self,k):

返回元素at index k

如果不为0< = k< self.n:
return IndexError('K超出范围!')#检查k索引是否在范围内数组

return self.A [k]#从索引k的数组中检索

def append(self,ele):

将元素添加到数组$ b的末尾$ b
,如果self.n == self.capacity:
self._resize(2 * self.capacity)#如果没有足够的空间,则加倍容量

self。 A [self.n] = ele#将self.n索引设置为元素
self.n + = 1

def _resize(self,new_cap):

将内部数组调整为容量new_cap

print(已调整大小!)

B = self.make_array(new_cap)#新更大数组

对于范围(self.n)中的k:#引用所有现有值
B [k] = self.A [k]

self.A = B#调用A更大的新数组
self.capacity = new_cap#重置容量

def make_array(self,new_cap):

返回一个新数组具有new_cap容量

ret ur(new_cap * ctypes.py_object)()

def __sizeof __(self):
返回0

用于测试调整大小的代码:

  arr2 = DynamicArray()

import sys

for i在范围(100)中:
print(len(arr2),,sys.getsizeof(arr2))
arr2.append (i)

输出:

  0 24 
1 24
调整大小!
2 24
调整大小!
3 24
4 24
调整大小!
5 24
6 24
7 24
8 24
调整大小!
9 24
10 24
11 24
12 24
13 24
14 24
15 24
16 24
调整大小!
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
调整大小称为!
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
调整大小!
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


解决方案

您的 __ sizeof __ 调用,它只是增加了垃圾收集器的开销,这就是为什么结果不为零的原因。



来自<$ c上的文档$ c> sys.getsizeof


getsizeof()调用对象的 __ sizeof __ 方法,并在对象i被添加时增加额外的垃圾收集器开销


返回 0 是一种方法因为您总是会得到相同的结果( 0 +开销),所以您很难理解自己的名字。



根据动态数组的内容返回大小以查看其变化。






进一步详细说明:



CPython中的每个对象在 PyGC_head struct 已添加的

  / *添加gc_head大小* / 
如果(PyObject_IS_GC(o))
返回((size_t)size)+ sizeof(PyGC_Head);
return(size_t)size;

由垃圾收集器使用。



为什么将其添加到整体大小中可能是因为它确实表示对象所需的额外内存。在Python级别上,您无需担心垃圾的收集并将其全部视为魔术,但是,当询问有关对象大小的信息时,您不应牺牲正确的结果只是为了保持幻觉。 / p>

I'm writing a dynamic array implementation in Python (similar to the built-in list class), for which I need to observe the growth in capacity (which doubles each time the limit is reached). For that I have the following code, but the output is weird. It looks like the sys.getsizeof() never calls my class's __sizeof__(). For the purpose of testing, I'm making the __sizeof__() return 0, but as per sys.getsizeof() it is non-zero.

What's the catch?

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

The code used to test the resizing:

arr2 = DynamicArray()

import sys

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

And the output:

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

解决方案

Your __sizeof__ is getting called, it's just adding the garbage collector overhead to it which is why the result isn't zero.

From the docs on sys.getsizeof:

getsizeof() calls the object’s __sizeof__ method and adds an additional garbage collector overhead if the object is managed by the garbage collector.

Returning 0 is one way in which you make it hard for your self to understand that it's called since you'll always get the same result back (0 + overhead).

Return a size based on the contents of the dynamic array to see it change.


To further elaborate:

Each object in CPython has some administrative information attached to it in a PyGC_head struct that gets added:

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

that is used by the garbage collector.

Why this is added to the overall size is probably because it does represent additional memory required by the object. On the Python level, you don't need to worry about the collection of garbage and treat it all like magic, but, when asking for information on the size of an object you should not sacrifice correct results just to keep the illusion alive.

这篇关于__sizeof__没有被sys.getsizeof调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆