Skip to content

Instantly share code, notes, and snippets.

@zzzeek
Created February 16, 2022 16:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zzzeek/82819a5d9f98b9f698ff8dfc626f42ca to your computer and use it in GitHub Desktop.
Save zzzeek/82819a5d9f98b9f698ff8dfc626f42ca to your computer and use it in GitHub Desktop.
get the actual recursive size of arbitrary objects
# taken from https://code.activestate.com/recipes/577504/ **plus**
# the comment at https://code.activestate.com/recipes/577504/#c5
from sys import getsizeof, stderr
from itertools import chain
from collections import deque
from reprlib import repr
def total_size(o, handlers={}, verbose=False):
dict_handler = lambda d: chain.from_iterable(d.items())
all_handlers = {
tuple: iter,
list: iter,
deque: iter,
dict: dict_handler,
set: iter,
frozenset: iter,
}
all_handlers.update(handlers) # user handlers take precedence
seen = set() # track which object id's have already been seen
default_size = getsizeof(0) # estimate sizeof object without __sizeof__
def sizeof(o):
if id(o) in seen: # do not double count the same object
return 0
seen.add(id(o))
s = getsizeof(o, default_size)
if verbose:
print(s, type(o), repr(o), file=stderr)
for typ, handler in all_handlers.items():
if isinstance(o, typ):
s += sum(map(sizeof, handler(o)))
break
else:
if not hasattr(o.__class__, "__slots__"):
if hasattr(o, "__dict__"):
# no __slots__ *usually* means a __dict__, but some
# special builtin classes (such as `type(None)`) have
# neither
s += sizeof(o.__dict__)
# else, `o` has no attributes at all, so sys.getsizeof()
# actually returned the correct value
else:
s += sum(
sizeof(getattr(o, x))
for x in o.__class__.__slots__
if hasattr(o, x)
)
return s
return sizeof(o)
class Foo:
__slots__ = ("foo",)
class FooDict:
__slots__ = "foo", "__dict__"
class Bar:
pass
slotted = Foo()
slotted.foo = "bar"
slotted_dict = FooDict()
slotted_dict.foo = "bar"
slotted_dict_dyn = FooDict()
slotted_dict_dyn.foo = "bar"
slotted_dict_dyn.dyn = "x"
slotted_dict_dyn.dyn2 = "y"
not_slotted = Bar()
not_slotted.foo = "bar"
not_slotted.bigger = "asdfasfsfads "
print(total_size(slotted))
print(total_size(slotted_dict))
print(total_size(slotted_dict_dyn))
print(total_size(not_slotted))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment