Wie bestimme ich die Größe eines Objekts in Python?

Lesezeit: 15 Minuten

Benutzer-Avatar
Benutzer46646

Ich möchte wissen, wie man die Größe von Objekten wie einer Zeichenfolge, einer Ganzzahl usw. in Python erhält.

Verwandte Frage: Wie viele Bytes pro Element enthält eine Python-Liste (Tupel)?

Ich verwende eine XML-Datei, die Größenfelder enthält, die die Größe des Werts angeben. Ich muss dieses XML analysieren und meine Codierung durchführen. Wenn ich den Wert eines bestimmten Felds ändern möchte, überprüfe ich das Größenfeld dieses Werts. Hier möchte ich vergleichen, ob der neue Wert, den ich eingeben soll, die gleiche Größe wie in XML hat. Ich muss die Größe des neuen Werts überprüfen. Im Falle einer Schnur kann ich sagen, dass es die Länge ist. Aber im Falle von int, float usw. bin ich verwirrt.

Benutzer-Avatar
nosklo

Verwenden Sie einfach die sys.getsizeof Funktion definiert in der sys Modul.

sys.getsizeof(object[, default]):

Gibt die Größe eines Objekts in Bytes zurück. Das Objekt kann ein beliebiger Objekttyp sein. Alle integrierten Objekte geben korrekte Ergebnisse zurück, dies muss jedoch nicht für Erweiterungen von Drittanbietern gelten, da dies implementierungsspezifisch ist.

Nur der direkt dem Objekt zugeordnete Speicherverbrauch wird berücksichtigt, nicht der Speicherverbrauch von Objekten, auf die es sich bezieht.

Das default Das Argument erlaubt es, einen Wert zu definieren, der zurückgegeben wird, wenn der Objekttyp keine Mittel zum Abrufen der Größe bereitstellt und eine verursachen würde
TypeError.

getsizeof ruft das Objekt auf
__sizeof__ -Methode und fügt einen zusätzlichen Garbage Collector-Overhead hinzu, wenn das Objekt vom Garbage Collector verwaltet wird.

Sehen rekursive Rezeptgröße für ein Anwendungsbeispiel getsizeof() rekursiv, um die Größe von Containern und all ihren Inhalten zu finden.

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

Wenn Sie in Python < 2.6 sind und nicht haben sys.getsizeof Sie können verwenden dieses umfangreiche Modul stattdessen. Habe es aber nie benutzt.

  • Bitte fügen Sie dem Haftungsausschluss hinzu, dass dies nicht für verschachtelte Objekte oder verschachtelte Diktate oder Diktate in Listen usw. gilt.

    – JohnnyM

    16. August 2015 um 9:22 Uhr

  • @ChaimG das liegt daran, dass jedes Objekt nur 32 Bytes verwendet !! Der Rest sind Verweise auf andere Objekte. Wenn Sie die referenzierten Objekte berücksichtigen möchten, müssen Sie definieren __sizeof__ Methode für Ihre Klasse. Das eingebaute dict Die Python-Klasse definiert es, deshalb erhalten Sie das richtige Ergebnis, wenn Sie ein Objekt vom Typ verwenden dict.

    – nosklo

    11. April 2017 um 17:23 Uhr


  • Der Haftungsausschluss und die Ausnahmen zu dieser Arbeit decken fast alle Anwendungsfälle ab, die die getsizeof Funktion von geringem Wert out of the box.

    – Robino

    28. Juni 2017 um 16:57 Uhr

  • Warum wird die Ganzzahl 2 in 24 Bytes gespeichert?

    – Saher Ahwal

    19. März 2018 um 23:59 Uhr

  • @SaherAhwal es ist nicht nur eine Ganzzahl, sondern ein vollständiges Objekt mit Methoden, Attributen, Adressen …

    – nosklo

    20. März 2018 um 17:29 Uhr

Benutzer-Avatar
Russland muss Putin entfernen

Wie bestimme ich die Größe eines Objekts in Python?

Die Antwort: „Einfach verwenden sys.getsizeof“, ist keine vollständige Antwort.

Diese Antwort tut direkt für eingebaute Objekte arbeiten, aber es berücksichtigt nicht, was diese Objekte enthalten können, insbesondere welche Typen, wie z. B. benutzerdefinierte Objekte, Tupel, Listen, Diktate und Mengen, enthalten sind. Sie können sowohl Instanzen als auch Zahlen, Zeichenfolgen und andere Objekte enthalten.

Eine vollständigere Antwort

Unter Verwendung von 64-Bit-Python 3.6 aus der Anaconda-Distribution mit sys.getsizeofhabe ich die Mindestgröße der folgenden Objekte bestimmt und bemerke, dass Sets und Diktate Speicherplatz vorbelegen, sodass leere nicht wieder wachsen, bis nach einer festgelegten Menge (die je nach Implementierung der Sprache variieren kann):

Python3:

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.

Wie interpretieren Sie das? Angenommen, Sie haben ein Set mit 10 Artikeln. Wenn jedes Element 100 Bytes groß ist, wie groß ist die gesamte Datenstruktur? Der Satz selbst ist 736, weil er einmal auf 736 Bytes vergrößert wurde. Dann addieren Sie die Größe der Elemente, also insgesamt 1736 Byte

Einige Einschränkungen für Funktions- und Klassendefinitionen:

Beachten Sie, dass jede Klassendefinition einen Proxy hat __dict__ (48 Byte) Struktur für Klassenattr. Jeder Slot hat einen Deskriptor (wie a property) in der Klassendefinition.

Slot-Instanzen beginnen mit 48 Byte auf ihrem ersten Element und erhöhen sich um jeweils 8 Bytes. Nur leere Slotted-Objekte haben 16 Byte, und eine Instanz ohne Daten macht sehr wenig Sinn.

Außerdem hat jede Funktionsdefinition Codeobjekte, vielleicht Docstrings, und andere mögliche Attribute, sogar a __dict__.

Beachten Sie auch, dass wir verwenden sys.getsizeof() weil wir uns um die marginale Speicherplatznutzung kümmern, die den Garbage-Collection-Overhead für das Objekt beinhaltet, aus den Dokumenten:

getsizeof() ruft das Objekt auf __sizeof__ -Methode und fügt einen zusätzlichen Garbage Collector-Overhead hinzu, wenn das Objekt vom Garbage Collector verwaltet wird.

Beachten Sie auch, dass das Ändern der Größe von Listen (z. B. wiederholtes Anhängen an sie) dazu führt, dass sie Speicherplatz vorbelegen, ähnlich wie bei Sets und Diktaten. Von dem listobj.c-Quellcode:

    /* 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);

Historische Daten

Python 2.7-Analyse, bestätigt mit guppy.hpy und 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.

Beachten Sie, dass Wörterbücher (aber keine Sätze) hat ein kompaktere Darstellung in Python 3.6

Ich denke, 8 Bytes pro zusätzlichem Element, auf das verwiesen werden soll, sind auf einem 64-Bit-Computer sehr sinnvoll. Diese 8 Bytes zeigen auf die Stelle im Speicher, an der sich das enthaltene Element befindet. Die 4 Bytes haben eine feste Breite für Unicode in Python 2, wenn ich mich richtig erinnere, aber in Python 3 wird str zu einem Unicode mit einer Breite, die der maximalen Breite der Zeichen entspricht.

Weitere Informationen zu Spielautomaten finden Sie in dieser Antwort.

Eine vollständigere Funktion

Wir wollen eine Funktion, die die Elemente in Listen, Tupeln, Sets, Diktaten sucht, obj.__dict__‘s, und obj.__slots__sowie andere Dinge, an die wir vielleicht noch nicht gedacht haben.

Darauf wollen wir uns verlassen gc.get_referents diese Suche durchzuführen, weil sie auf C-Ebene funktioniert (was sie sehr schnell macht). Der Nachteil ist, dass get_referents redundante Mitglieder zurückgeben kann, also müssen wir sicherstellen, dass wir nicht doppelt zählen.

Klassen, Module und Funktionen sind Singletons – sie existieren einmal im Speicher. Ihre Größe interessiert uns nicht so sehr, da können wir nicht viel dagegen tun – sie sind Teil des Programms. Wir vermeiden es also, sie zu zählen, wenn auf sie verwiesen wird.

Wir werden eine schwarze Liste von Typen verwenden, damit wir nicht das gesamte Programm in unsere Größenzählung aufnehmen.

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

Um dies der folgenden Whitelist-Funktion gegenüberzustellen, wissen die meisten Objekte, wie sie sich zum Zwecke der Garbage Collection selbst durchlaufen (was ungefähr das ist, wonach wir suchen, wenn wir wissen möchten, wie teuer bestimmte Objekte im Speicher sind. Diese Funktionalität wird von verwendet gc.get_referents.) Allerdings wird diese Maßnahme weitaus umfangreicher ausfallen, als wir beabsichtigt haben, wenn wir nicht aufpassen.

Beispielsweise wissen Funktionen ziemlich viel über die Module, in denen sie erstellt werden.

Ein weiterer Kontrastpunkt ist, dass Zeichenfolgen, die Schlüssel in Wörterbüchern sind, normalerweise interniert werden, damit sie nicht dupliziert werden. Überprüfung auf id(key) ermöglicht es uns auch, das Zählen von Duplikaten zu vermeiden, was wir im nächsten Abschnitt tun. Die Blacklist-Lösung überspringt das Zählen von Schlüsseln, die Zeichenfolgen sind, insgesamt.

Whitelist-Typen, rekursiver Besucher

Die meisten dieser Typen zu decken, anstatt sich auf die zu verlassen gc -Modul habe ich diese rekursive Funktion geschrieben, um zu versuchen, die Größe der meisten Python-Objekte abzuschätzen, einschließlich der meisten Builtins, Typen im Collections-Modul und benutzerdefinierter Typen (slotted und andere).

Diese Art von Funktion bietet eine viel genauere Kontrolle über die Typen, die wir für die Speichernutzung zählen, birgt jedoch die Gefahr, dass wichtige Typen ausgelassen werden:

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)

Und ich habe es eher beiläufig getestet (ich sollte es unittesten):

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

Diese Implementierung bricht auf Klassendefinitionen und Funktionsdefinitionen zusammen, weil wir nicht nach all ihren Attributen suchen, aber da sie für den Prozess nur einmal im Speicher existieren sollten, spielt ihre Größe wirklich keine allzu große Rolle.

  • Sie könnten hinzufügen, dass diese Antwort spezifisch für CPython ist (was impliziert wird, wenn Sie Python über Anaconda erhalten).

    – Gerrit

    1. April 2019 um 15:16 Uhr

  • CPython ist die Referenzimplementierung, und ich habe gerade die Online-Dokumentation von jython überprüft, die dieselbe API bereitstellen. Ich glaube also, dass dies bei anderen Implementierungen funktionieren wird, solange sie die APIs implementieren.

    – Russland muss Putin entfernen

    1. April 2019 um 17:06 Uhr

  • für mich funktionierte es nicht für maskierte und unmaskierte numpy-Arrays stackoverflow.com/q/58675479/2132157

    – GR

    2. November 2019 um 23:32 Uhr

  • Dies scheint ein BloomFilter-Objekt als 120 Byte darzustellen, unabhängig davon, was darin enthalten ist …? pyprobables.readthedocs.io/en/latest/code.html#bloomfilter

    – d8aninja

    28. Juli 2020 um 12:46 Uhr

  • Jedes in C implementierte benutzerdefinierte Objekt, das nicht richtig implementiert wird __sizeof__ wird nicht mit funktionieren sys.getsizeofund dies ist nicht gut dokumentiert, da es als Implementierungsdetail betrachtet wird (siehe bugs.python.org/issue15436). Erwarten Sie nicht, dass diese Funktion alles abdeckt – passen Sie sie nach Bedarf an Ihre Anwendungsfälle an.

    – Russland muss Putin entfernen

    28. Juli 2020 um 16:53 Uhr

Benutzer-Avatar
serv-inc

Das Pympler Pakete asizeof Modul kann das.

Verwenden Sie wie folgt:

from pympler import asizeof
asizeof.asizeof(my_object)

nicht wie sys.getsizeofes arbeitet für Ihre selbst erstellten Objekte. Es funktioniert sogar mit 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

Wie erwähnt,

Die (Byte-)Codegröße von Objekten wie Klassen, Funktionen, Methoden, Modulen usw. kann per Einstellungsoption eingeschlossen werden code=True.

Und wenn Sie eine andere Sicht auf Live-Daten benötigen, Pympler’s

Modul muppy wird für die Online-Überwachung einer Python-Anwendung und eines Python-Moduls verwendet Class Tracker bietet eine Offline-Analyse der Lebensdauer ausgewählter Python-Objekte.

  • Diese Funktion ist für größere Objekte ziemlich langsam. Gibt es ein “schnelles” Äquivalent, das für selbst erstellte Objekte funktioniert?

    – Shuklaswag

    7. Juni 2017 um 18:42 Uhr

  • @Shuklaswag: Wenn Sie Funken verwenden, könnte dies durchaus der Fall sein. Denkst du die Conversion + Java-Schätzung ist schneller als die integrierten Methoden von Python? Oder habe ich das falsch verstanden?

    – serv-inc

    8. Juni 2017 um 16:28 Uhr

  • Das ist vielleicht erwähnenswert pympler verfügt über die Fähigkeit, die Größe des ausführbaren Codes von Funktionen und anderen aufrufbaren und Codeobjekten zu berücksichtigen.

    – mtraceur

    15. März 2018 um 8:22 Uhr

  • Die Ergebnisse sind in Byte, kByte, MByte …?

    – Ich habe keine Ahnung

    26. März 2020 um 1:51 Uhr

  • @ihavenoidea: Bytes (Stellen Sie sich vor, jedes Python-Objekt benötigt 280 kByte)

    – serv-inc

    27. März 2020 um 10:03 Uhr

Für numpy Arrays, getsizeof funktioniert nicht – für mich gibt es aus irgendeinem Grund immer 40 zurück:

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

Dann (in Ipython):

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

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

Zum Glück aber:

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

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

Benutzer-Avatar
Arco Bast

Sie können das Objekt serialisieren, um ein Maß abzuleiten, das eng mit der Größe des Objekts zusammenhängt:

import pickle

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

Wenn Sie Objekte messen möchten, die nicht gebeizt werden können (z. B. aufgrund von Lambda-Ausdrücken), können Dill oder Cloudpickle eine Lösung sein.

  • Ich finde das am einfachsten und nützlichsten, vor allem, weil ich mich am meisten um die Python-Objektgröße kümmere, wenn ich sie serialisieren muss (für Multiprozess usw.).

    – StatsNoob

    14. April 2021 um 23:17 Uhr

  • Funktioniert nicht, wenn ein numpy Slice Speicher belegt. Wie in import numpy as np; a = np.arange(100000000); b = a[2:4]; del a; len(pickle.dumps(b)) # 150, but the array is 100MB or more depending on the dtype

    – Torben545

    18. Oktober 2021 um 9:25 Uhr


  • Ein weiterer Fall, in dem dies nicht funktioniert: TypeError: cannot pickle '_thread.lock' object — werde versuchen dill/cloudpickle wie vorgeschlagen!

    – Avi Vajpeyi

    12. Juli um 18:22 Uhr


Verwenden sys.getsizeof() wenn Sie KEINE Größen von verknüpften (verschachtelten) Objekten einbeziehen möchten.

Wenn Sie jedoch Unterobjekte zählen möchten, die in Listen, Diktaten, Sätzen, Tupeln verschachtelt sind – und normalerweise ist DAS das, wonach Sie suchen – verwenden Sie die rekursive tiefe Größe von () Funktion wie unten gezeigt:

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

Diese Funktion finden Sie auch in der raffiniert Toolbox, zusammen mit vielen anderen nützlichen Einzeilern:

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

  • Ich finde das am einfachsten und nützlichsten, vor allem, weil ich mich am meisten um die Python-Objektgröße kümmere, wenn ich sie serialisieren muss (für Multiprozess usw.).

    – StatsNoob

    14. April 2021 um 23:17 Uhr

  • Funktioniert nicht, wenn ein numpy Slice Speicher belegt. Wie in import numpy as np; a = np.arange(100000000); b = a[2:4]; del a; len(pickle.dumps(b)) # 150, but the array is 100MB or more depending on the dtype

    – Torben545

    18. Oktober 2021 um 9:25 Uhr


  • Ein weiterer Fall, in dem dies nicht funktioniert: TypeError: cannot pickle '_thread.lock' object — werde versuchen dill/cloudpickle wie vorgeschlagen!

    – Avi Vajpeyi

    12. Juli um 18:22 Uhr


Benutzer-Avatar
VonC

Python 3.8 (Q1 2019) wird einige der Ergebnisse von ändern sys.getsizeofwie hier angekündigt von Raymond Hettinger:

Python-Container sind bei 64-Bit-Builds 8 Byte kleiner.

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

Das kommt danach Ausgabe 33597 und Inada Naoki (methane)‘s Arbeit um Compact PyGC_Head und PR-7043

Diese Idee reduziert die Größe von PyGC_Head auf zwei Wörter.

Derzeit nimmt PyGC_Head drei Wörter; gc_prev, gc_nextund gc_refcnt.

  • gc_refcnt wird beim Sammeln, zum Probelöschen verwendet.
  • gc_prev wird zum Tracking und Untracking verwendet.

Wenn wir also das Tracking/Untracking während der Testlöschung vermeiden können, gc_prev und gc_refcnt denselben Speicherplatz teilen können.

Sehen d5c875b übergeben:

Eine entfernt Py_ssize_t Mitglied aus PyGC_Head.
Die Größe aller GC-verfolgten Objekte (z. B. Tupel, Liste, Diktat) wird um 4 oder 8 Byte reduziert.

1143700cookie-checkWie bestimme ich die Größe eines Objekts in Python?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy