python - text用法 - plt xlim




我如何確定Python中對象的大小? (6)

我如何確定Python中對象的大小?

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

這個答案直接適用於內建對象,但它沒有考慮這些對象可能包含的內容,特別是包含元組,列表,字典和集合等類型。 它們可以包含實例,以及數字,字符串和其他對象。

更完整的答案

使用來自Anaconda發行版的64位Python 2.7以及與guppy.hpy一起的sys.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個字節指向包含的項目所在的內存中的位置。 如果我記得正確,4個字節是Python 2中unicode的固定寬度,但在Python 3中,str變為寬度等於字符最大寬度的unicode。

(有關插槽的更多信息, 請參閱此答案 )

遞歸訪問者獲得更完整的功能

為了覆蓋大部分這些類型,我編寫了這個遞歸函數來嘗試估計大多數Python對象的大小,包括大部分內建函數,collections模塊中的類型以及自定義類型(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)

我測試它很隨便(我應該單元測試):

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

它在類定義和函數定義上有所分解,因為我沒有去追踪它們的所有屬性,但是因為它們只應該在內存中存在一次,所以它們的大小實際上並不重要。

在C中,我們可以找到intchar等的大小。我想知道如何在Python中獲取像字符串,整數等對象的大小。

相關問題: Python列表(元組)中每個元素有多少個字節?

我正在使用包含指定值大小的大小字段的XML文件。 我必須解析這個XML並進行編碼。 當我想要更改特定字段的值時,我將檢查該值的大小字段。 在這裡我想比較一下我輸入的新值是否與XML中的大小相同。 我需要檢查新值的大小。 如果是字符串,我可以說它的長度。 但在int,float等情況下,我很困惑。


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

mentioned

通過設置選項code=True ,可以包括諸如類,函數,方法,模塊等對象的(字節)代碼大小。

如果您需要關於實時數據的其他觀點,Pympler的

module muppy用於在線監控Python應用程序和模塊Class Tracker提供離線分析選定Python對象的生命週期。


只需使用sys模塊中定義的sys.getsizeof函數即可。

sys.getsizeof(object[, default])

以字節為單位返回對象的大小。 該對象可以是任何類型的對象。 所有內置對像都會返回正確的結果,但這不一定適用於第三方擴展,因為它是特定於實現的。

default參數允許定義一個值,如果對像類型沒有提供檢索大小的方法並且會導致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你可以使用這個擴展模塊 。 從來沒有使用它。


如果有人遇到這個問題,需要比sys.getsizeof或Aaron Hall提供的程序更“防彈”的解決方案,這裡有一個配方,試圖以原則和靈活的方式處理類和字節碼對像等問題(不幸的是,複製或有意義地總結這段時間太長了)。


自己多次遇到這個問題後,我寫了一個小函數(靈感來自@ aaron-hall的回答)和測試,這些都符合我所期望的sys.getsize的功能:

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

這可能比看起來更複雜,取決於你想如何計算東西。 例如,如果您有一個整數列表,您是否希望列表的大小包含對整數的引用 ? (即僅列表,而不是其中包含的內容),還是希望包含指向的實際數據,在這種情況下,您需要處理重複引用,以及如何防止在兩個對象包含引用時重複計算同一個對象。

您可能需要查看一下python內存分析器,比如pysizer ,看看它們是否滿足您的需求。





sizeof