programing

Python에서 오브젝트의 크기를 확인하는 방법은 무엇입니까?

itsource 2022. 9. 21. 22:10
반응형

Python에서 오브젝트의 크기를 확인하는 방법은 무엇입니까?

Python에서 문자열, 정수 등의 오브젝트 크기를 얻는 방법을 알고 싶습니다.

관련 질문:Python 목록(태플)에는 요소당 몇 바이트가 있습니까?

값의 크기를 지정하는 크기 필드가 포함된 XML 파일을 사용하고 있습니다.이 XML을 해석하고 코딩해야 합니다.특정 필드의 값을 변경하고 싶을 때 해당 값의 크기 필드를 확인합니다.여기서 입력하는 새 값이 XML과 같은 크기인지 비교합니다. 새 값의 크기를 확인해야 합니다.끈의 경우 길이라고 할 수 있습니다.단, int, float 등의 경우나는 혼란스럽다.

에 정의된 기능을 사용하면 됩니다.sys★★★★★★ 。

sys.getsizeof(object[, default]):

개체의 크기(바이트)를 반환합니다.개체는 모든 유형의 개체일 수 있습니다.모든 기본 제공 개체는 올바른 결과를 반환하지만, 구현에 따라 다르므로 타사 확장에 대해서는 해당되지 않을 수 있습니다.

객체에 직접 기인하는 메모리 소비량만 설명되며 객체가 참조하는 객체의 메모리 소비량은 설명되지 않습니다.

default하는 수단을 , 「」의 이 되는 할 수 .TypeError.

getsizeof「」를 합니다.__sizeof__method 및 오브젝트가 가비지 컬렉터에 의해 관리되는 경우 가비지 컬렉터의 오버헤드를 추가합니다.

사용 예는 레시피의 재귀 크기를 참조하십시오.getsizeof()재귀적으로 용기의 크기와 모든 내용물을 찾습니다.

사용 예: 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

. 6python < 2 . 6 이 don't if 。sys.getsizeof대신 이 광범위한 모듈을 사용할 수 있습니다.써본 적은 없지만.

Python에서 오브젝트의 크기를 확인하는 방법은 무엇입니까?

쓰세요' 입니다sys.getsizeof'이렇게 하다'

답변은 빌트인 객체에 대해 직접 작동하지만 이러한 객체에 포함할 수 있는 내용, 특히 커스텀 객체, 튜플, 목록, 딕트 및 집합과 같은 유형은 고려하지 않습니다.여기에는 서로 인스턴스, 숫자, 문자열 및 기타 개체가 포함될 수 있습니다.

보다 완전한 답변

3.과 Anaconda의 64비트 Python 3.6을 sys.getsizeof다음 오브젝트의 최소 사이즈를 확인했습니다.또한 빈 공간은 설정량(언어 구현에 따라 달라질 수 있음)이 경과할 때까지 다시 증가하지 않도록 사전에 할당되어 있습니다.

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바이트로 1회 사이징되었기 때문에 그 자체입니다.그리고 아이템의 크기를 더하면 총 1736바이트가 됩니다.

함수 및 클래스 정의에 대한 몇 가지 경고:

.__dict__ 바이트) attributes (48 바이트) 입니다.등가.property★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

슬롯 인스턴스는 첫 번째 요소에서 48바이트로 시작하여 추가될 때마다 8바이트씩 증가합니다.빈 슬롯 개체만 16바이트이며 데이터가 없는 인스턴스는 의미가 없습니다.

또한 각 오브젝트,및 Atribute가 또, 「 」, 「 」, 「 」, 「 」라고 하는 어트리뷰트도 있습니다.__dict__.

, 「」, 「」를 사용하고 있는 것에 해 주세요.sys.getsizeof()오브젝트의 가비지 수집 오버헤드를 포함한 다음 문서의 한계 공간 사용량에 주목하기 때문입니다.

getsizeof()「」를 합니다.__sizeof__method 및 오브젝트가 가비지 컬렉터에 의해 관리되는 경우 가비지 컬렉터의 오버헤드를 추가합니다.

또한 목록 크기 조정(예: 목록에 반복적으로 추가됨)은 집합 및 딕트와 마찬가지로 공간을 미리 할당합니다.listobj.c 소스 코드:

    /* This over-allocates proportional to the list size, making room
     * for additional growth.  The over-allocation is mild, but is
     * enough to give linear-time amortized behavior over a long
     * sequence of appends() in the presence of a poorly-performing
     * system realloc().
     * The growth pattern is:  0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
     * Note: new_allocated won't overflow because the largest possible value
     *       is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
     */
    new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);

이력 데이터

2.7 Python 2.7로 , Python 2.7 분석, 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에서 더 콤팩트하게 표현되었습니다.

64비트 머신에서는 추가 참조 항목당 8바이트가 매우 타당하다고 생각합니다.이 8바이트는 메모리 내의 포함된 항목이 있는 위치를 가리킵니다.Python 2에서는 4바이트가 고정폭이지만 Python 3에서는 str이 최대폭과 같은 폭의 유니코드가 됩니다.

슬롯에 대한 자세한 내용은 다음 답변을 참조하십시오.

보다 완전한 기능

세트,, ,, ,, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, 트, we, 트, we, we, we, we, we, we in, lists, , obj.__dict__ »obj.__slots__그리고 우리가 아직 생각하지 못했던 다른 것들도 있다.

하고 싶습니다.gc.get_referentsC레벨에서 동작하기 때문에 이 검색을 실행할 수 있습니다(매우 고속화).단점은 get_refresents가 다중 멤버를 반환할 수 있기 때문에 이중 카운트를 하지 않도록 해야 한다는 것입니다.

클래스, 모듈 및 함수는 싱글톤이며 메모리에 한 번 존재합니다.우리는 그들의 크기에 그다지 관심이 없습니다. 왜냐하면 그들에 대해 우리가 할 수 있는 일이 많지 않기 때문입니다. 그들은 프로그램의 일부이기 때문입니다.그래서 만약 그들이 언급된다면 우리는 그들을 세지 않을 것이다.

전체 프로그램을 크기 수에 포함하지 않도록 유형의 블랙리스트를 사용합니다.

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

이를 다음 화이트리스트 기능과 대조하기 위해 대부분의 개체는 가비지 수집을 위해 자신을 트래버스하는 방법을 알고 있습니다(특정 개체의 메모리 가격이 얼마인지 알고 싶을 때 대략적으로 알고 있습니다).은 this기 this this이 this this this this this this this this 。gc.get_referents그러나 이 조치는 우리가 조심하지 않으면 우리가 의도한 것보다 훨씬 범위가 넓어질 것이다.

예를 들어 함수는 작성된 모듈에 대해 상당히 많은 것을 알고 있습니다.

또 다른 대조점은 사전의 키인 문자열은 보통 중복되지 않도록 삽입되어 있다는 것입니다. forid(key)또, 중복되는 카운트를 회피할 수 있습니다(다음 항에서 실시합니다.블랙리스트 솔루션은 문자열인 키 수를 모두 건너뜁니다.

화이트리스트 유형, 재귀 방문자

을 제가 직접 수 하기 .gcmodule, 이 재귀 함수는 대부분의 Python 객체의 크기를 추정하기 위해 작성되었습니다.여기에는 대부분의 빌트인, 컬렉션 모듈의 유형, 커스텀 유형(슬롯 및 기타)이 포함됩니다.

이러한 종류의 함수는 메모리 사용량에 대해 고려할 유형을 훨씬 더 세밀하게 제어할 수 있지만, 중요한 유형을 제외할 위험이 있습니다.

import sys
from numbers import Number
from collections import deque
from collections.abc import Set, Mapping


ZERO_DEPTH_BASES = (str, bytes, Number, range, bytearray)


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, 'items'):
            size += sum(inner(k) + inner(v) for k, v in getattr(obj, 'items')())
        # 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

이 구현은 클래스 정의와 함수 정의를 세분화합니다.왜냐하면 이 속성들의 모든 것을 쫓는 것은 아니기 때문입니다.다만, 이러한 속성들은 프로세스의 메모리에 1회만 존재해야 하기 때문에, 그 크기는 그다지 중요하지 않습니다.

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.

모듈은 Python 응용 프로그램의 온라인 모니터링에 사용되며 모듈은 선택한 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

개체를 직렬화하여 개체 크기와 밀접하게 관련된 측정을 도출할 수 있습니다.

import pickle

## let o be the object whose size you want to measure
size_estimate = len(pickle.dumps(o))

예를 들어 람다 식 때문에 절일 수 없는 객체를 측정하려는 경우 딜 또는 클라우드피클이 해결책이 될 수 있습니다.

링크된(네스트된) 개체의 크기를 포함하지 않으려면 sys.getsizeof()사용합니다.

단, 목록, dict, set, tuples에 중첩된 서브오브젝트를 카운트하고 싶다면 다음과 같이 recursive deep sizeof() 함수를 사용합니다.

import sys
def sizeof(obj):
    size = sys.getsizeof(obj)
    if isinstance(obj, dict): return size + sum(map(sizeof, obj.keys())) + sum(map(sizeof, obj.values()))
    if isinstance(obj, (list, tuple, set, frozenset)): return size + sum(map(sizeof, obj))
    return size

이 기능은 다른 유용한 원라인과 함께 니프티 툴박스에서 찾을 수 있습니다.

https://github.com/mwojnars/nifty/blob/master/util.py

Python 3.8(2019년 1분기)은 Raymond Hettinger에 의해 다음과 같이 결과 중 일부를 변경합니다.

Python 컨테이너는 64비트 빌드에서 8바이트 더 작습니다.

tuple ()  48 -> 40       
list  []  64 ->56
set()    224 -> 216
dict  {} 240 -> 232

33597호 이나다 나오키 ()methane의 Compact PyGC_Head 및 PR 7043에 관한 연구 입니다.

이 아이디어는 PyGC_Head 크기를 두 단어로 줄입니다.

현재 PyGC_Head는 3단어를 사용합니다.gc_prev,gc_next , , , , 입니다.gc_refcnt.

  • gc_refcnt수집 시 평가판 삭제에 사용됩니다.
  • gc_prev을 사용하다

삭제 에 트래킹할 수 , 추추추추면/면면면면면면 면면면면gc_prev ★★★★★★★★★★★★★★★★★」gc_refcnt는 같은 메모리 공간을 공유할 수 있습니다.

commit d5c875b참조해 주세요.

를를삭 1개 제거.Py_ssize_t★★★★★★★★★★★★★★★★의PyGC_Head.
모든 GC 추적 대상 개체(예: 튜플, 목록, 딕트) 크기가 4 또는 8바이트 감소합니다.

이것은 당신이 어떻게 계산하고 싶은지에 따라 보기보다 더 복잡할 수 있다.를 들어,ints, 에 대한 참조를 포함하는 목록의 크기를 지정하시겠습니까?int ( 또는 된 실제 이참조를 해야 하며 두 개체에 에 된 경우 이중 하는 방법을 하십시오.(예: 목록에 포함된 내용이 아닌 목록만 해당) 또는 지적된 실제 데이터를 포함하려면 이 경우 중복 참조를 처리해야 하며 두 개체에 동일한 개체에 대한 참조가 포함된 경우 이중 중복을 방지하는 방법을 지정하십시오.

pysizer와 같은 python 메모리 프로파일러 중 하나를 살펴보고 사용자의 요구를 충족하는지 확인하는 것이 좋습니다.

저는 이 문제에 여러 번 부딪혔기 때문에 작은 함수(@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)) )

python 객체의 실제 크기를 가져오려면 다음 함수를 사용합니다.

import sys
import gc

def actualsize(input_obj):
    memory_size = 0
    ids = set()
    objects = [input_obj]
    while objects:
        new = []
        for obj in objects:
            if id(obj) not in ids:
                ids.add(id(obj))
                memory_size += sys.getsizeof(obj)
                new.append(obj)
        objects = gc.get_referents(*new)
    return memory_size

actualsize([1, 2, [3, 4, 5, 1]])

참고 자료: https://towardsdatascience.com/the-strange-size-of-python-objects-in-memory-ce87bdfbb97f

개체의 정확한 크기가 필요하지 않지만 개체의 크기를 대략적으로 알 수 있다면, 이 특정 파이썬 프로세스를 통해 프로그램을 실행하고, 장시간 절전 모드로 전환하고, 메모리 사용량(예: Mac의 활동 모니터)을 확인하는 것이 한 가지 빠르고 더러운 방법입니다.이것은 파이썬 프로세스에서 하나의 큰 개체의 크기를 찾으려 할 때 효과적입니다.예를 들어, 저는 최근에 새로운 데이터 구조의 메모리 사용량을 확인하고 Python의 데이터 구조의 메모리 용량과 비교하고 싶었습니다.먼저 요소(대규모 퍼블릭 도메인 북의 단어)를 세트에 쓰고 프로세스의 크기를 확인한 후 다른 데이터 구조에서도 같은 작업을 수행했습니다.Python 프로세스가 새로운 데이터 구조보다 2배의 메모리를 사용하고 있는 것을 알게 되었습니다.다시 말씀드리지만 프로세스에서 사용되는 메모리가 개체의 크기와 동일하다고 정확하게 말할 수는 없습니다.개체의 크기가 커지면 나머지 프로세스에서 사용하는 메모리가 모니터링하려는 개체의 크기에 비해 무시해도 될 정도로 줄어들기 때문에 개체의 크기가 커집니다.

난 이 수법을 쓴다...작은 오브젝트에서는 정확하지 않지만, sys.getsizeof()보다는 복잡한 오브젝트(pygame surface 등)가 훨씬 정확하다고 생각합니다.

import pygame as pg
import os
import psutil
import time


process = psutil.Process(os.getpid())
pg.init()    
vocab = ['hello', 'me', 'you', 'she', 'he', 'they', 'we',
         'should', 'why?', 'necessarily', 'do', 'that']

font = pg.font.SysFont("monospace", 100, True)

dct = {}

newMem = process.memory_info().rss  # don't mind this line
Str = f'store ' + f'Nothing \tsurface use about '.expandtabs(15) + \
      f'0\t bytes'.expandtabs(9)  # don't mind this assignment too

usedMem = process.memory_info().rss

for word in vocab:
    dct[word] = font.render(word, True, pg.Color("#000000"))

    time.sleep(0.1)  # wait a moment

    # get total used memory of this script:
    newMem = process.memory_info().rss
    Str = f'store ' + f'{word}\tsurface use about '.expandtabs(15) + \
          f'{newMem - usedMem}\t bytes'.expandtabs(9)

    print(Str)
    usedMem = newMem

Windows 10의 python 3.7.3에서는 다음과 같이 출력됩니다.

store hello          surface use about 225280    bytes
store me             surface use about 61440     bytes
store you            surface use about 94208     bytes
store she            surface use about 81920     bytes
store he             surface use about 53248     bytes
store they           surface use about 114688    bytes
store we             surface use about 57344     bytes
store should         surface use about 172032    bytes
store why?           surface use about 110592    bytes
store necessarily    surface use about 311296    bytes
store do             surface use about 57344     bytes
store that           surface use about 110592    bytes

퍼포먼스가 문제가 되지 않는 경우, 가장 쉬운 해결책은 피클을 사용하여 다음을 측정하는 것입니다.

import pickle

data = ...
len(pickle.dumps(data))

다음과 같이 getSizeof()를 사용하여 객체의 크기를 결정할 수 있습니다.

import sys
str1 = "one"
int_element=5
print("Memory size of '"+str1+"' = "+str(sys.getsizeof(str1))+ " bytes")
print("Memory size of '"+ str(int_element)+"' = "+str(sys.getsizeof(int_element))+ " bytes")

언급URL : https://stackoverflow.com/questions/449560/how-do-i-determine-the-size-of-an-object-in-python

반응형