我如何确定在Python中的对象的大小?

在C中,我们可以findintchar等的大小。我想知道如何在Python中获取像string,整数等对象的大小。

相关的问题: Python列表(元组)中每个元素有多less个字节?

我正在使用包含指定值大小的大小字段的XML文件。 我必须parsing这个XML并做我的编码。 当我想要改变特定字段的值时,我将检查该值的大小字段。 这里我想比较一下,我input的新值是否与XML中的大小相同。 我需要检查新值的大小。 在string的情况下,我可以说它的长度。 但在int,float等情况下,我很困惑。

只需使用sys模块中定义的sys.getsizeof函数即可。

sys.getsizeof(object[, default])

以字节为单位返回对象的大小。 该对象可以是任何types的对象。 所有的内置对象都会返回正确的结果,但这并不一定适用于第三方扩展,因为它是特定于实现的。

default参数允许定义一个值,如果对象types没有提供检索大小的方法并且会导致TypeError ,将返回一个值。

getsizeof调用对象的__sizeof__方法,并添加额外的垃圾回收器开销,如果对象由垃圾回收器pipe理。

用法示例,在python 3.0中:

 >>> import sys >>> x = 2 >>> sys.getsizeof(x) 14 >>> sys.getsizeof(sys.getsizeof) 32 >>> sys.getsizeof('this') 38 >>> sys.getsizeof('this also') 48 

如果你在python <2.6并没有sys.getsizeof你可以使用这个广泛的模块来代替。 从来没有使用它。

我如何确定在Python中的对象的大小?

答案是“只使用sys.getsizeof”不是一个完整的答案。

这个答案直接适用于内build对象,但是它并不包含那些对象可能包含的内容,具体来说,包含元组,列表,字典和集合等types。 它们可以包含实例,以及数字,string和其他对象。

更完整的答案

在Anaconda发行版中使用64位Python 2.7,以及使用sys.getsizeofsys.getsizeof ,我已经确定了以下对象的最小大小,并且注意到sets和dicts预先分配空间,所以空的不会再增长,直到一组金额(可能因语言的实施而有所不同):

 Bytes type empty + scaling notes 24 int NA 28 long NA 37 str + 1 byte per additional character 52 unicode + 4 bytes per additional character 56 tuple + 8 bytes per additional item 72 list + 32 for first, 8 for each additional 232 set sixth item increases to 744; 22nd, 2280; 86th, 8424 280 dict sixth item increases to 1048; 22nd, 3352; 86th, 12568 * 64 class inst has a __dict__ attr, same scaling as dict above 16 __slots__ class with slots has no dict, seems to store in mutable tuple-like structure. 120 func def doesn't include default args and other attrs 904 class def has a proxy __dict__ structure for class attrs 104 old class makes sense, less stuff, has real dict though. 

*请注意,字典( 但不是集合 )在Python 3.6中获得更紧凑的表示

我认为每个引用的附加项目8个字节在64位机器上有很大的意义。 这8个字节指向包含的项目所在的内存中的位置。 在Python 2中,4个字节是unicode的固定宽度,如果我记得正确,但是在Python 3中,str变成一个宽度等于字符最大宽度的unicode。

(对于更多的插槽, 看到这个答案 )

recursion访问者获得更完整的function

为了覆盖大部分这些types,我写了这个recursion函数来试图估计大多数Python对象的大小,包括大部分内build函数,collections模块中的types和自定义types(slotted和other):

 import sys from numbers import Number from collections import Set, Mapping, deque try: # Python 2 zero_depth_bases = (basestring, Number, xrange, bytearray) iteritems = 'iteritems' except NameError: # Python 3 zero_depth_bases = (str, bytes, Number, range, bytearray) iteritems = 'items' def getsize(obj_0): """Recursively iterate to sum size of object & members.""" def inner(obj, _seen_ids = set()): obj_id = id(obj) if obj_id in _seen_ids: return 0 _seen_ids.add(obj_id) size = sys.getsizeof(obj) if isinstance(obj, zero_depth_bases): pass # bypass remaining control flow and return elif isinstance(obj, (tuple, list, Set, deque)): size += sum(inner(i) for i in obj) elif isinstance(obj, Mapping) or hasattr(obj, iteritems): size += sum(inner(k) + inner(v) for k, v in getattr(obj, iteritems)()) # Check for custom object instances - may subclass above too if hasattr(obj, '__dict__'): size += inner(vars(obj)) if hasattr(obj, '__slots__'): # can have __slots__ with __dict__ size += sum(inner(getattr(obj, s)) for s in obj.__slots__ if hasattr(obj, s)) return size return inner(obj_0) 

而且我testing它很随便(我应该unit testing):

 >>> getsize(['a', tuple('bcd'), Foo()]) 344 >>> getsize(Foo()) 16 >>> getsize(tuple('bcd')) 194 >>> getsize(['a', tuple('bcd'), Foo(), {'foo': 'bar', 'baz': 'bar'}]) 752 >>> getsize({'foo': 'bar', 'baz': 'bar'}) 400 >>> getsize({}) 280 >>> getsize({'foo':'bar'}) 360 >>> getsize('foo') 40 >>> class Bar(): ... def baz(): ... pass >>> getsize(Bar()) 352 >>> getsize(Bar().__dict__) 280 >>> sys.getsizeof(Bar()) 72 >>> getsize(Bar.__dict__) 872 >>> sys.getsizeof(Bar.__dict__) 280 

在类定义和函数定义方面有些差异,因为我没有去追踪它们的所有属性,但是因为它们只能在内存中存在一次,所以它们的大小实际上并不重要。

对于numpy数组, getsizeof不起作用 – 对我来说总是返回40,原因是:

 from pylab import * from sys import getsizeof A = rand(10) B = rand(10000) 

然后(在ipython中):

 In [64]: getsizeof(A) Out[64]: 40 In [65]: getsizeof(B) Out[65]: 40 

令人高兴的是,

 In [66]: A.nbytes Out[66]: 80 In [67]: B.nbytes Out[67]: 80000 

Pympler包的asizeof模块可以做到这一点。

使用方法如下:

 from pympler import asizeof asizeof.asizeof(my_object) 

不像sys.getsizeof ,它适用于你自己创build的对象 。 它甚至与numpy一起工作。

 >>> asizeof.asizeof(tuple('bcd')) 200 >>> asizeof.asizeof({'foo': 'bar', 'baz': 'bar'}) 400 >>> asizeof.asizeof({}) 280 >>> asizeof.asizeof({'foo':'bar'}) 360 >>> asizeof.asizeof('foo') 40 >>> asizeof.asizeof(Bar()) 352 >>> asizeof.asizeof(Bar().__dict__) 280 >>> A = rand(10) >>> B = rand(10000) >>> asizeof.asizeof(A) 176 >>> asizeof.asizeof(B) 80096 

这可能比看起来更复杂,取决于你想如何计算的东西。 例如,如果您有一个整数列表,是否需要包含对整数的引用的列表的大小? (即仅列表,而不是包含在其中),或者是否要包含指向的实际数据,在这种情况下,您需要处理重复的引用,以及如何在两个对象包含引用时防止重复计算同一个对象。

你可能想看一下python内存分析器,比如pysizer ,看看它们是否满足你的需求。

这里是我写的一个快速脚本,基于以前对所有variables列表大小的回答

 for i in dir(): try: print (i, eval(i).nbytes ) except: print (i, sys.getsizeof(eval(i)) ) 

如果有人遇到这个问题,需要比sys.getsizeof或Aaron Hall提供的程序更“防弹”的解决scheme,这里有一个方法,试图以原则和灵活的方式处理诸如类和字节码对象的问题(不幸的是,复制或者有意义的总结太长了)。

自己遇到这个问题多次,我写了一个小函数(灵感来自@ aaron-hall的答案)和testing,做我所期望的sys.getsizeof做:

https://github.com/bosswissam/pysize

如果你对背景感兴趣的话, 那就是

编辑:附上下面的代码,以方便参考。 要查看最新的代码,请检查github链接。

  import sys def get_size(obj, seen=None): """Recursively finds size of objects""" size = sys.getsizeof(obj) if seen is None: seen = set() obj_id = id(obj) if obj_id in seen: return 0 # Important mark as seen *before* entering recursion to gracefully handle # self-referential objects seen.add(obj_id) if isinstance(obj, dict): size += sum([get_size(v, seen) for v in obj.values()]) size += sum([get_size(k, seen) for k in obj.keys()]) elif hasattr(obj, '__dict__'): size += get_size(obj.__dict__, seen) elif hasattr(obj, '__iter__') and not isinstance(obj, (str, bytes, bytearray)): size += sum([get_size(i, seen) for i in obj]) return size 

您可以使用资源模块来测量当前进程的最大驻留集大小的更改,如下所示:

  import resource usage = resource.getrusage(resource.RUSAGE_SELF) maxrss_before = getattr(usage, 'ru_maxrss') your_object = func_to_create_your_object() maxrss_after = getattr(usage, 'ru_maxrss') print(maxrss_after - maxrss_before) 

第一:答案。

 import sys try: print sys.getsizeof(object) except AttributeError: print "sys.getsizeof exists in Python ≥2.6" 

讨论:
在Python中,你永远不能访问“直接的”内存地址。 那么为什么你需要或想知道一个给定的对象占用了多less这样的地址? 这个抽象层面的问题完全不合适。 当你在画房子的时候,你不会问光线被光线吸收或reflection的频率是多less,你只要问它是什么颜色 – 创build这种颜色的物理特征的细节在旁边。 类似地,一个给定的Python对象占用的内存字节数在这一点之外。

那么,为什么你要用Python来编写C代码呢? 🙂