当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《如何在Python中确定对象的大小?》经验,为你挑选了8个好方法。

在C中,我们可以找到的大小int,char等我想知道如何获得物体的大小就像一个字符串,整数,等在Python.

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

我使用的XML文件包含指定值大小的大小字段.我必须解析这个XML并进行编码.当我想更改特定字段的值时,我将检查该值的大小字段.在这里,我想比较一下我输入的新值是否与XML中的值相同.我需要检查新值的大小.在字符串的情况下,我可以说它的长度.但是在int,float等的情况下我很困惑.



1> nosklo..:

只需使用模块中定义的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你可以使用这个扩展模块.从来没有用过它.


请添加免责声明,它不适用于嵌套对象或列表中的嵌套dicts或dicts等.
这项工作的免责声明和例外几乎涵盖了所有使用`getsizeof`功能的开箱即用功能.
@ChaimG那是因为每个对象只使用32个字节!! 其余的是对其他对象的引用.如果要考虑引用的对象,则必须为类定义`__sizeof__`方法.内置的`dict` python类确实定义了它,这就是为什么在使用`dict`类型的对象时得到正确的结果.
嗯...即使类实例有50个属性,sys.sizeof(c)也是32!似乎有些东西!试试这个:`d = {k:v for k,v in zip('ABCDEFGHIJKLMNOPQRSTUVWXYabcdefghijklmnopqrstuvwxy',range(50))}``class C(object):def __init __(self,**kwargs):_ = {setattr( self,k,v)for k,v in kwargs.items()}``c = C(**d)``sys.getsizeof(d)`1676`sys.getsizeof(c)`32
@SaherAhwal它不仅仅是一个整数,而是一个包含方法,属性,地址的完整对象......
为什么整数2存储在24个字节中?

2> Aaron Hall..:
如何在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)

它有点打破了类定义和函数定义,因为我没有追求它们的所有属性,但由于它们应该只在内存中存在一次,因此它们的大小确实无关紧要.


您可能还添加了此答案特定于CPython(这是通过Anaconda获取Python所隐含的)

3> serv-inc..:

该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对象生命周期的离线分析.


可能值得注意的是,`pympler`具有将函数的可执行代码大小以及其他callables和代码对象考虑在内的能力.

4> Mike Dewar..:

对于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


"如果您使用的是numpy数组(http://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html),那么您可以使用属性'ndarray.nbytes'来评估其在内存中的大小." http://stackoverflow.com/a/15591157/556413
>所有内置对象都将返回正确的结果,但这不一定适用于第三方扩展,因为它是特定于实现的.http://docs.python.org/library/sys.html#sys.getsizeof
我猜测40个字节是正确的,但是`getsizeof()`只给你对象的大小(数组的标题),而不是里面的数据.同样的python容器`sys.getsizeof([1,2,4])== sys.getsizeof([1,123**456,4])== 48`,而`sys.getsizeof(123**456)= 436`
似乎“ getsizeof()”函数在某个时候被更改以返回期望值。

5> Brian..:

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

您可能需要查看其中一个python内存分析器,例如pysizer,看看它们是否满足您的需求.



6> VonC..:

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_prevgc_nextgc_refcnt

gc_refcnt 收集时用于尝试删除。

gc_prev 用于跟踪和取消跟踪。

因此,如果我们可以避免在尝试删除时进行跟踪/取消跟踪,gc_prev并且gc_refcnt可以共享相同的内存空间。

参见commit d5c875b:

Py_ssize_t从中删除一名成员PyGC_Head
所有GC跟踪的对象(例如,元组,列表,字典)的大小都减少了4或8个字节。



7> 小智..:

我自己多次遇到这个问题,我写了一个小函数(灵感来自@ 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



8> alexey..:

这是我根据以前对所有变量列表大小的答案编写的快速脚本

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

推荐阅读
落单鸟人
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有