在C中,我们可以找到的大小int
,char
等我想知道如何获得物体的大小就像一个字符串,整数,等在Python.
相关问题:Python列表(元组)中每个元素有多少字节?
我使用的XML文件包含指定值大小的大小字段.我必须解析这个XML并进行编码.当我想更改特定字段的值时,我将检查该值的大小字段.在这里,我想比较一下我输入的新值是否与XML中的值相同.我需要检查新值的大小.在字符串的情况下,我可以说它的长度.但是在int,float等的情况下我很困惑.
只需使用模块中定义的sys.getsizeof函数即可sys
.
sys.getsizeof(object[, default])
:以字节为单位返回对象的大小.对象可以是任何类型的对象.所有内置对象都将返回正确的结果,但这不一定适用于第三方扩展,因为它是特定于实现的.
该
default
参数允许定义一个值,如果对象类型没有提供检索大小的方法并将导致a,将返回该值TypeError
.
getsizeof
__sizeof__
如果对象由垃圾收集器管理,则调用该对象的 方法并添加额外的垃圾收集器开销.
用法示例,在python 3.0中:
>>> import sys >>> x = 2 >>> sys.getsizeof(x) 24 >>> sys.getsizeof(sys.getsizeof) 32 >>> sys.getsizeof('this') 38 >>> sys.getsizeof('this also') 48
如果你在python <2.6但没有,sys.getsizeof
你可以使用这个扩展模块.从来没有用过它.
如何在Python中确定对象的大小?
答案"只使用sys.getsizeof"并不是一个完整的答案.
这个问题的答案并不直接内置对象的工作,但它并没有占到什么这些对象可能包含,具体是什么类型,比如元组,列表类型的字典,并设置包含.它们可以包含彼此的实例,以及数字,字符串和其他对象.
更完整的答案使用来自Anaconda发行版的64位Python 3.6,使用sys.getsizeof,我确定了以下对象的最小大小,并注意set和dicts预分配空间,因此空的不会再次增长,直到设定量(可能因语言的实现而有所不同):
Python 3:
Empty
Bytes type scaling notes
28 int +4 bytes about every 30 powers of 2
37 bytes +1 byte per additional byte
49 str +1-4 per additional character (depending on max width)
48 tuple +8 per additional item
64 list +8 for each additional
224 set 5th increases to 736; 21nd, 2272; 85th, 8416; 341, 32992
240 dict 6th increases to 368; 22nd, 1184; 43rd, 2280; 86th, 4704; 171st, 9320
136 func def does not include default args and other attrs
1056 class def no slots
56 class inst has a __dict__ attr, same scaling as dict above
888 class def with slots
16 __slots__ seems to store in mutable tuple-like structure
first slot grows to 48, and so on.
你怎么解释这个?好吧,你有一套10件物品.如果每个项目每个100字节,整个数据结构有多大?该集合本身就是736,因为它的大小为736字节.然后添加项目的大小,总共1736个字节
函数和类定义的一些注意事项:
注意每个类定义都有__dict__
类attrs 的代理(48字节)结构.每个槽property
在类定义中都有一个描述符(如a ).
Slotted实例在其第一个元素上以48个字节开始,每个额外增加8个.只有空的开槽对象有16个字节,而没有数据的实例几乎没有意义.
此外,每个函数定义都有代码对象,可能是文档字符串,以及其他可能的属性,甚至是__dict__
.
Python 2.7分析,用guppy.hpy
和确认sys.getsizeof
:
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 *
120 func def does not include default args and other attrs
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.
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个字节指向包含项目所在的内存中的位置.如果我没记错的话,4字节是Python 2中unicode的固定宽度,但在Python 3中,str变成宽度等于字符最大宽度的unicode.
(有关插槽的更多信息,请参阅此答案)
递归访问者以获得更完整的功能为了覆盖大多数这些类型,我编写了这个递归函数来尝试估计大多数Python对象的大小,包括大多数内置函数,集合模块中的类型和自定义类型(插槽和其他):
import sys from types import ModuleType, FunctionType from gc import get_referents # Custom objects know their class. # Function objects seem to know way too much, including modules. # Exclude modules as well. BLACKLIST = type, ModuleType, FunctionType def getsize(obj): """sum size of object & members.""" if isinstance(obj, BLACKLIST): raise TypeError('getsize() does not take argument of type: '+ str(type(obj))) seen_ids = set() size = 0 objects = [obj] while objects: need_referents = [] for obj in objects: if not isinstance(obj, BLACKLIST) and id(obj) not in seen_ids: seen_ids.add(id(obj)) size += sys.getsizeof(obj) need_referents.append(obj) objects = get_referents(*need_referents) return size
而且我很随便地测试它(我应该对它进行单元测试):
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.""" _seen_ids = set() def inner(obj): 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)
它有点打破了类定义和函数定义,因为我没有追求它们的所有属性,但由于它们应该只在内存中存在一次,因此它们的大小确实无关紧要.
该Pympler封装的asizeof
模块可以做到这一点.
使用方法如下:
from pympler import asizeof asizeof.asizeof(my_object)
sys.getsizeof
与之不同,它适用于您自己创建的对象.它甚至适用于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
正如提到的,
通过设置选项可以包括类,函数,方法,模块等对象的(字节)代码大小
code=True
.
如果你需要有关实时数据的其他观点,那就是Pympler's
module
muppy
用于在线监视Python应用程序,模块Class Tracker
提供所选Python对象生命周期的离线分析.
对于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
这可能比看起来更复杂,具体取决于你想要计算的东西.例如,如果你有一个int列表,你想要包含对int 的引用的列表的大小吗?(即仅列出,不包含其中的内容),或者是否要包含指向的实际数据,在这种情况下,您需要处理重复的引用,以及当两个对象包含对引用的引用时如何防止重复计数同一个对象.
您可能需要查看其中一个python内存分析器,例如pysizer,看看它们是否满足您的需求.
Raymond Hettinger 在此宣布sys.getsizeof
,Python 3.8(2019年第一季度)将更改的某些结果:
在64位版本中,Python容器要小8字节。
tuple () 48 -> 40 list [] 64 ->56 set() 224 -> 216 dict {} 240 -> 232
这是在问题33597和Inada Naoki(methane
)围绕Compact PyGC_Head和PR 7043开展的工作之后
这个想法将PyGC_Head的大小减少到两个单词。
目前,PyGC_Head包含三个词;
gc_prev
,gc_next
和gc_refcnt
。
gc_refcnt
收集时用于尝试删除。
gc_prev
用于跟踪和取消跟踪。
因此,如果我们可以避免在尝试删除时进行跟踪/取消跟踪,
gc_prev
并且gc_refcnt
可以共享相同的内存空间。
参见commit d5c875b:
已
Py_ssize_t
从中删除一名成员PyGC_Head
。
所有GC跟踪的对象(例如,元组,列表,字典)的大小都减少了4或8个字节。
我自己多次遇到这个问题,我写了一个小函数(灵感来自@ aaron-hall的答案)和测试,它做了我原本希望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
这是我根据以前对所有变量列表大小的答案编写的快速脚本
for i in dir(): print (i, sys.getsizeof(eval(i)) )