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.
__sizeof__
metodę dla swojej klasy. Wbudowanadict
klasa python to definiuje, dlatego otrzymujesz poprawny wynik, używając obiektu typudict
.getsizeof
funkcja o niewielkiej wartości jest dostępna od razu po wyjęciu z pudełka.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:
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 aproperty
) 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 :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 :
Dane historyczne
Analiza Python 2.7, potwierdzona za pomocą
guppy.hpy
isys.getsizeof
: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__
iobj.__slots__
innych rzeczach, o których jeszcze nie myśleliśmy.Chcemy polegać na
gc.get_referents
tym 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.
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:
I przetestowałem to raczej od niechcenia (powinienem to powtórzyć):
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.
źródło
W Pympler pakiet za
asizeof
moduł może to zrobić.Użyj w następujący sposób:
W przeciwieństwie do
sys.getsizeof
tego działa dla twoich samodzielnie stworzonych obiektów . Działa nawet z Numpy.Jak wspomniano ,
A jeśli potrzebujesz innego widoku danych na żywo, Pympler
źródło
org.apache.spark.util.SizeEstimator
może być odpowiednipympler
ma możliwości uwzględnienia wykonywalnego kodu funkcji oraz innych wywołań i obiektów kodu.TypeError
wyją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?W przypadku tablic numpy
getsizeof
nie działa - dla mnie zawsze zwraca 40 z jakiegoś powodu:Następnie (w ipython):
Na szczęście jednak:
źródło
getsizeof()
podaje tylko rozmiar obiektu (nagłówek tablicy), a nie danych w nim zawartych. To samo dotyczy kontenerów python, gdziesys.getsizeof([1,2,4]) == sys.getsizeof([1,123**456,4]) == 48
, podczas gdysys.getsizeof(123**456) = 436
getsizeof()
funkcja została w pewnym momencie zmieniona, aby zwrócić oczekiwaną wartość.Python 3.8 (pierwszy kwartał 2019 r.) Zmieni niektóre wyniki
sys.getsizeof
, jak zapowiedział Raymond Hettinger:Dzieje się tak po numerze 33597 i pracach Inady Naoki (
methane
) wokół Compact PyGC_Head i PR 7043Zobacz zatwierdzenie d5c875b :
źródło
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.
źródło
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.
źródło
Oto krótki skrypt, który napisałem na podstawie wcześniejszych odpowiedzi na listę rozmiarów wszystkich zmiennych
źródło
Możesz serializować obiekt, aby uzyskać miarę ściśle związaną z rozmiarem obiektu:
Jeśli chcesz mierzyć obiekty, które nie mogą być marynowane (np. Z powodu wyrażeń lambda), cloudpickle może być rozwiązaniem.
źródło
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:
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
źródło
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ć.
źródło
Możesz użyć getSizeof () jak wspomniano poniżej, aby określić rozmiar obiektu
źródło
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 ()
W moim systemie Windows 10, python 3.7.3, dane wyjściowe są następujące:
źródło