Jak określić rozmiar obiektu w Pythonie?


683

Chcę wiedzieć, jak uzyskać rozmiar obiektów, takich jak ciąg, liczba całkowita itp. W Pythonie.

Powiązane pytanie: ile bajtów na element znajduje się na liście Python (krotka)?

Korzystam z pliku XML, który zawiera pola wielkości określające rozmiar wartości. Muszę przeanalizować ten kod XML i wykonać kodowanie. Kiedy chcę zmienić wartość określonego pola, sprawdzę pole rozmiaru tej wartości. Tutaj chcę porównać, czy nowa wartość, którą chcę wprowadzić, ma taki sam rozmiar jak w XML. Muszę sprawdzić rozmiar nowej wartości. W przypadku łańcucha mogę powiedzieć, że jest to długość. Ale w przypadku int, float itp. Jestem zdezorientowany.

Odpowiedzi:


665

Wystarczy użyć funkcji sys.getsizeof zdefiniowanej w sysmodule.

sys.getsizeof(object[, default]):

Zwraca rozmiar obiektu w bajtach. Obiekt może być dowolnym rodzajem obiektu. Wszystkie wbudowane obiekty zwrócą prawidłowe wyniki, ale nie musi to być prawdziwe w przypadku rozszerzeń innych firm, ponieważ jest ono specyficzne dla implementacji.

defaultArgumentem pozwala określić wartość, która zostanie zwrócona, jeśli typ obiektu nie przewiduje oznacza pobieranie rozmiaru i będzie powodować TypeError.

getsizeofwywołuje __sizeof__metodę obiektu i dodaje dodatkowy narzut na śmieci, jeśli obiekt jest zarządzany przez śmieciarz.

Przykład użycia w Pythonie 3.0:

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

Jeśli używasz Pythona <2.6 i nie masz go sys.getsizeof, możesz zamiast tego użyć tego obszernego modułu . Nigdy tego nie użyłem.


182
Dodaj do zrzeczenia się, że nie będzie to prawdą dla zagnieżdżonych obiektów lub zagnieżdżonych nagrań lub nagrań na listach itp.
JohnnyM

8
@ChaimG to dlatego, że każdy obiekt używa tylko 32 bajtów !! Reszta to odniesienia do innych obiektów. Jeśli chcesz uwzględnić obiekty, do których istnieją odniesienia, musisz zdefiniować __sizeof__metodę dla swojej klasy. Wbudowana dictklasa python to definiuje, dlatego otrzymujesz poprawny wynik, używając obiektu typu dict.
nosklo 11.04.17

19
Wyłączenie odpowiedzialności i wyjątki od tej pracy obejmują prawie wszystkie przypadki użycia, dzięki czemu getsizeoffunkcja o niewielkiej wartości jest dostępna od razu po wyjęciu z pudełka.
Robino

7
dlaczego liczba całkowita 2 jest przechowywana w 24 bajtach?
Saher Ahwal

4
@ SaherAhwal to nie tylko liczba całkowita, ale pełny obiekt z metodami, atrybutami, adresami ...
nosklo

370

Jak określić rozmiar obiektu w Pythonie?

Odpowiedź „Po prostu użyj sys.getsizeof” nie jest pełną odpowiedzią.

Że odpowiedź nie praca dla wbudowanego polecenia obiektów bezpośrednio, ale nie bierze pod uwagę tego, co te obiekty mogą zawierać, w szczególności, jakie typy obiektów, takich jak niestandardowe krotek, list dicts i zestawy zawierają. Mogą zawierać między sobą wystąpienia, a także liczby, ciągi znaków i inne obiekty.

Bardziej kompletna odpowiedź

Korzystając z 64-bitowego Pythona 3.6 z dystrybucji Anaconda, wraz z sys.getsizeof, określiłem minimalny rozmiar następujących obiektów i zauważam, że zestawy i dyktują wstępnie przydzielone miejsce, więc puste nie rosną, dopóki nie osiągną ustalonej ilości (co może zależy od implementacji języka):

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.

Jak to interpretujesz? Powiedzmy, że masz zestaw z 10 przedmiotami. Jeśli każdy element ma po 100 bajtów, jak duża jest cała struktura danych? Sam zestaw to 736, ponieważ raz zwiększył rozmiar do 736 bajtów. Następnie dodajesz rozmiar elementów, więc w sumie jest to 1736 bajtów

Niektóre zastrzeżenia dotyczące definicji funkcji i klas:

Uwaga: każda definicja klasy ma strukturę proxy __dict__(48 bajtów) dla attrów klas. Każdy slot ma deskryptor (jak a property) w definicji klasy.

Instancje szczelinowe zaczynają się od 48 bajtów na pierwszym elemencie i zwiększają się o 8 każdego dodatkowego. Tylko puste obiekty szczelinowe mają 16 bajtów, a instancja bez danych ma bardzo mały sens.

Ponadto każda definicja funkcji ma obiekty kodu, może dokumenty i inne możliwe atrybuty, nawet a __dict__.

Zauważ też, że używamy, sys.getsizeof()ponieważ dbamy o wykorzystanie przestrzeni marginalnej, która obejmuje narzut związany z odśmiecaniem obiektu, z dokumentów :

getsizeof () wywołuje __sizeof__metodę obiektu i dodaje dodatkowy narzut na śmieci, jeżeli obiekt jest zarządzany przez śmieciarz.

Zauważ też, że zmiana rozmiaru list (np. Powtarzające się dołączanie do nich) powoduje, że wstępnie przydzielają miejsce, podobnie jak zestawy i dykt. Z kodu źródłowego 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);

Dane historyczne

Analiza Python 2.7, potwierdzona za pomocą guppy.hpyi 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.

Zauważ, że słowniki ( ale nie zestawy ) mają bardziej zwartą reprezentację w Pythonie 3.6

Myślę, że 8 bajtów na dodatkowy element do odniesienia ma sens na 64-bitowej maszynie. Te 8 bajtów wskazuje miejsce w pamięci, w którym znajduje się zawarty element. 4 bajty mają stałą szerokość dla Unicode w Pythonie 2, jeśli dobrze pamiętam, ale w Pythonie 3, str staje się Unicode o szerokości równej maksymalnej szerokości znaków.

(Więcej informacji na temat automatów znajdziesz w tej odpowiedzi )

Bardziej kompletna funkcja

Chcemy funkcji, która przeszukuje elementy na listach, krotkach, zestawach, słownikach obj.__dict__i obj.__slots__innych rzeczach, o których jeszcze nie myśleliśmy.

Chcemy polegać na gc.get_referentstym wyszukiwaniu, ponieważ działa na poziomie C (dzięki czemu jest bardzo szybki). Minusem jest to, że get_referents może zwracać zbędnych członków, więc musimy upewnić się, że się nie liczymy.

Klasy, moduły i funkcje są singletonami - istnieją raz w pamięci. Nie interesuje nas ich rozmiar, ponieważ niewiele możemy z nimi zrobić - są częścią programu. Unikniemy ich liczenia, jeśli zdarzy się, że zostaną do nich odniesienia.

Użyjemy czarnej listy typów, więc nie uwzględniamy całego programu w naszym liczniku rozmiarów.

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

Aby to porównać z następującą funkcją z białej listy, większość obiektów wie, jak się przemieszczać w celu wyrzucania elementów bezużytecznych (co jest w przybliżeniu tym, czego szukamy, gdy chcemy wiedzieć, jak drogie są niektóre obiekty w pamięci. Z tej funkcji korzystają gc.get_referents.) Jednak środek ten będzie miał znacznie szerszy zakres niż zamierzaliśmy, jeśli nie będziemy ostrożni.

Na przykład funkcje dużo wiedzą o modułach, w których są tworzone.

Innym punktem kontrastowym jest to, że ciągi będące kluczami w słownikach są zwykle internalizowane, więc nie są duplikowane. Sprawdzanie id(key)pozwoli nam również uniknąć liczenia duplikatów, co zrobimy w następnej sekcji. Rozwiązanie czarnej listy całkowicie pomija liczenie kluczy, które są ciągami znaków.

Typy na białej liście, gość rekurencyjny (stara implementacja)

Aby pokryć większość z tych typów osobiście, zamiast polegać na module gc, napisałem tę funkcję rekurencyjną, aby spróbować oszacować rozmiar większości obiektów Pythona, w tym większości wbudowanych, typów w module kolekcji i typów niestandardowych (szczelinowych i innych) .

Ten rodzaj funkcji daje znacznie bardziej szczegółową kontrolę nad typami, które będziemy liczyć do użycia pamięci, ale grozi to pominięciem typów:

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)

I przetestowałem to raczej od niechcenia (powinienem to powtórzyć):

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

Ta implementacja dzieli się na definicje klas i definicji funkcji, ponieważ nie idziemy za wszystkimi ich atrybutami, ale ponieważ powinny one istnieć tylko raz w pamięci dla procesu, ich rozmiar naprawdę nie ma większego znaczenia.


5
Możesz dodać, że ta odpowiedź jest specyficzna dla CPython (co wynika z tego, że dostajesz Pythona przez
Anacondę

1
CPython jest implementacją referencyjną, a ja właśnie przejrzałem dokumenty online jython, które zapewniają ten sam interfejs API, więc wierzę, że zadziała to na innych implementacjach, o ile implementują one interfejsy API.
Aaron Hall

dla mnie nie działał dla zamaskowanych i zdemaskowanych tablic numpy stackoverflow.com/q/58675479/2132157
GM

96

W Pympler pakiet za asizeofmoduł może to zrobić.

Użyj w następujący sposób:

from pympler import asizeof
asizeof.asizeof(my_object)

W przeciwieństwie do sys.getsizeoftego działa dla twoich samodzielnie stworzonych obiektów . Działa nawet z 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

Jak wspomniano ,

Rozmiar (bajtowy) kodu obiektów, takich jak klasy, funkcje, metody, moduły itp. Można uwzględnić, ustawiając opcję code=True.

A jeśli potrzebujesz innego widoku danych na żywo, Pympler

moduł muppysłuży do monitorowania aplikacji Python on-line, a moduł Class Trackerzapewnia analizę czasu życia wybranych obiektów Python w trybie offline.


ta funkcja jest dość wolna w przypadku większych obiektów. Czy istnieje „szybki” odpowiednik, który działa dla samodzielnie tworzonych obiektów?
Shuklaswag

Jeszcze go nie testowałem, ale org.apache.spark.util.SizeEstimatormoże być odpowiedni
Shuklaswag

1
@Shuklaswag: jeśli używasz iskry, może być. Czy uważasz, że konwersja + oszacowanie Java jest szybsze niż wbudowane metody Pythona? A może źle zrozumiałem?
serv-inc

3
Warto zauważyć, że pymplerma możliwości uwzględnienia wykonywalnego kodu funkcji oraz innych wywołań i obiektów kodu.
mtraceur

Dostaję TypeErrorwyjątek: „Obiekt„ NoneType ”nie jest możliwy do wywołania”, ilekroć mój obiekt niestandardowy ma podobiektyw w „drzewie” z wartością None. Czy jest na to jakieś szybkie obejście?
James Hirschorn,

81

W przypadku tablic numpy getsizeofnie działa - dla mnie zawsze zwraca 40 z jakiegoś powodu:

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

Następnie (w ipython):

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

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

Na szczęście jednak:

In [66]: A.nbytes
Out[66]: 80

In [67]: B.nbytes
Out[67]: 80000

29
> Wszystkie wbudowane obiekty zwrócą poprawne wyniki, ale nie musi to być prawdziwe w przypadku rozszerzeń innych firm, ponieważ jest specyficzne dla implementacji. docs.python.org/library/sys.html#sys.getsizeof
warvariuc

33
„Jeśli używasz tablicy numpy ( docs.scipy.org/doc/numpy/reference/arrays.ndarray.html ), możesz użyć atrybutu„ ndarray.nbytes ”, aby ocenić jej rozmiar w pamięci.” stackoverflow.com/a/15591157/556413
glarrain

17
Sądzę, że 40 bajtów jest poprawnych, jednak getsizeof()podaje tylko rozmiar obiektu (nagłówek tablicy), a nie danych w nim zawartych. To samo dotyczy kontenerów python, gdzie sys.getsizeof([1,2,4]) == sys.getsizeof([1,123**456,4]) == 48, podczas gdysys.getsizeof(123**456) = 436
yota

3
Wygląda na to, że getsizeof()funkcja została w pewnym momencie zmieniona, aby zwrócić oczekiwaną wartość.
dshin

16

Python 3.8 (pierwszy kwartał 2019 r.) Zmieni niektóre wyniki sys.getsizeof, jak zapowiedział Raymond Hettinger:

Kontenery Python są o 8 bajtów mniejsze w 64-bitowych kompilacjach.

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

Dzieje się tak po numerze 33597 i pracach Inady Naoki ( methane) wokół Compact PyGC_Head i PR 7043

Ten pomysł zmniejsza rozmiar PyGC_Head do dwóch słów .

Obecnie PyGC_Head wymaga trzech słów ; gc_prev, gc_nexti gc_refcnt.

  • gc_refcnt jest używany podczas zbierania, do próbnego usunięcia.
  • gc_prev służy do śledzenia i wyśledzenia.

Więc jeśli możemy uniknąć śledzenia / wyśledzenia podczas usuwania wersji próbnej gc_previ gc_refcntmożemy współdzielić to samo miejsce w pamięci.

Zobacz zatwierdzenie d5c875b :

Usunięto jednego Py_ssize_tczłonka z PyGC_Head.
Rozmiar wszystkich śledzonych obiektów GC (np. Krotka, lista, dict) jest zmniejszony o 4 lub 8 bajtów.


14

Może to być bardziej skomplikowane, niż wygląda, w zależności od tego, jak chcesz policzyć rzeczy. Na przykład, jeśli masz listę ints, czy chcesz rozmiar listy zawierającej odwołania do ints? (tj. tylko lista, a nie to, co jest w niej zawarte), czy też chcesz dołączyć wskazane dane, w którym to przypadku musisz poradzić sobie ze zduplikowanymi referencjami i jak zapobiec podwójnemu liczeniu, gdy dwa obiekty zawierają odwołania do ten sam obiekt.

Możesz rzucić okiem na jeden z profilerów pamięci Python, taki jak pysizer, aby sprawdzić, czy spełniają twoje potrzeby.


10

Po wielokrotnym napotkaniu tego problemu napisałem małą funkcję (zainspirowaną odpowiedzią @ aaron-hall) i testy, które wykonują to, czego oczekiwałbym od sys.getsizeof:

https://github.com/bosswissam/pysize

Jeśli interesujesz się historią, oto ona

EDYCJA: Załączenie poniższego kodu dla łatwego odniesienia. Aby zobaczyć najbardziej aktualny kod, sprawdź link 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

7

Oto krótki skrypt, który napisałem na podstawie wcześniejszych odpowiedzi na listę rozmiarów wszystkich zmiennych

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

To nie jest złe, jest dwuznaczne. sys.getsizeof zawsze zwróci wartość jest potrzebna, więc nie ma potrzeby tracić wydajności z try..except.
der_fenix

och, to dobra uwaga i nie myślałem o tym - kod w obecnej formie pokazuje tylko, jak został napisany chronologicznie - najpierw wiedziałem o numpy (stąd nbytes), a potem szukałem bardziej ogólnego rozwiązania . Dziękuję za wyjaśnienie _ / \ _
alexey,

7

Możesz serializować obiekt, aby uzyskać miarę ściśle związaną z rozmiarem obiektu:

import pickle

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

Jeśli chcesz mierzyć obiekty, które nie mogą być marynowane (np. Z powodu wyrażeń lambda), cloudpickle może być rozwiązaniem.


4

Użyj sys.getsizeof (), jeśli NIE chcesz uwzględniać rozmiarów połączonych (zagnieżdżonych) obiektów.

Jeśli jednak chcesz liczyć podobiekty zagnieżdżone na listach, dyktach, zestawach, krotkach - i zwykle to jest to, czego szukasz - skorzystaj z rekurencyjnej funkcji deep sizeof (), jak pokazano poniżej:

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

Możesz również znaleźć tę funkcję w fajnym zestawie narzędzi, wraz z wieloma innymi przydatnymi liniami:

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


3

Jeśli nie potrzebujesz dokładnego rozmiaru obiektu, ale z grubsza wiesz, jak duży jest, jednym szybkim (i brudnym) sposobem jest uruchomienie programu, spanie przez dłuższy czas i sprawdzenie zużycia pamięci (np. : Monitor aktywności Maca) według tego konkretnego procesu Pythona. Byłoby to skuteczne, gdy próbujesz znaleźć rozmiar pojedynczego dużego obiektu w procesie Pythona. Na przykład ostatnio chciałem sprawdzić wykorzystanie pamięci w nowej strukturze danych i porównać ją ze strukturą danych ustawioną w Pythonie. Najpierw zapisałem elementy (słowa z dużej książki publicznej) do zestawu, następnie sprawdziłem rozmiar procesu, a następnie zrobiłem to samo z inną strukturą danych. Dowiedziałem się, że proces Pythona z zestawem zajmuje dwa razy więcej pamięci niż nowa struktura danych. Znowu nie zrobiłbyś być w stanie dokładnie powiedzieć, że pamięć używana przez proces jest równa wielkości obiektu. Gdy rozmiar obiektu staje się duży, staje się ono bliskie, ponieważ pamięć zużywana przez resztę procesu staje się znikoma w porównaniu do wielkości obiektu, który próbujesz monitorować.


1
Pytanie dotyczy tego, jak to zrobić w Pythonie , a nie tylko znalezienie użycia pamięci w obiektach Python, a używanie monitora aktywności komputera Mac lub innego podobnego oprogramowania nie jest programowo przy użyciu Pythona. Mając na uwadze powyższe, sprawdzając zużycie pamięci procesów Pythona w ten sposób ogólnie jest dobrym sposobem, aby upewnić się, że nic nie poszło źle ...
Tom Wyllie

@TomWyllie, dzięki, ale głosowanie w dół tej odpowiedzi niesie negatywne skojarzenie, że sama odpowiedź jest błędna i niczego nie osiąga. Metoda, o której wspomniałem, może nie zostać zaimplementowana w Pythonie, ale jest to przydatny sposób na zgrubne oszacowanie wielkości obiektu Pythona. Wiedziałem, że nie odpowiadam na dokładne pytanie, jednak metoda może być przydatna dla kogoś innego, aby uzyskać podobny wynik.
picmate 涅

1

Możesz użyć getSizeof () jak wspomniano poniżej, aby określić rozmiar obiektu

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

0

Używam tej sztuczki ... Może nie być dokładna na małych obiektach, ale myślę, że jest znacznie bardziej dokładna dla złożonych obiektów (takich jak powierzchnia gry) niż sys.getsizeof ()

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

W moim systemie Windows 10, python 3.7.3, dane wyjściowe są następujące:

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.