From the documentation (my bold) (a):
Only the memory consumption directly attributed to the object is accounted for, not the memory consumption of objects it refers to.
So the size of v
does not include the sizes of the elements it refers to.
If you change kite
into kites
, you'll also see that its size increases but not the size of v
(I've replaced your big number with 100...00
in the output to ease formatting):
1 size is: 12
2 size is: 12
kite size is: 25
100...00 size is: 102
Total size is: 48
1 size is: 12
2 size is: 12
kites size is: 26
100...00 size is: 102
Total size is: 48
Think of it like this:
/ +-----+
| v | ref | -> 1
Size | | ref | -> 2
of v | | ref | -> 'kite'
| | ref | -> 100**100
\ +-----+
\___________________________/
Size of things referred
to by v
(a) That page also has a link to a recipe for doing recursive size calculations if you need that information. The link is duplicated here for citation, and the code is duplicated below to make this answer more self-contained.
Plugging your structure into that code gives:
48 <type 'list'> [1, 2, 'kites', 100...00L]
12 <type 'int'> 1
12 <type 'int'> 2
26 <type 'str'> 'kites'
102 <type 'long'> 100...00L
200
The code, with your structure, is shown below.
from __future__ import print_function
from sys import getsizeof, stderr
from itertools import chain
from collections import deque
try:
from reprlib import repr
except ImportError:
pass
def total_size(o, handlers={}, verbose=False):
""" Returns the approximate memory footprint an object and all of its contents.
Automatically finds the contents of the following builtin containers and
their subclasses: tuple, list, deque, dict, set and frozenset.
To search other containers, add handlers to iterate over their contents:
handlers = {SomeContainerClass: iter,
OtherContainerClass: OtherContainerClass.get_elements}
"""
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
return s
return sizeof(o)
##### Example call #####
if __name__ == '__main__':
v = [1,2,'kites',100**100]
print(total_size(v, verbose=True))