3 # Copyright, license and disclaimer are at the very end of this file.
5 # This is the latest, enhanced version of the asizeof.py recipes at
6 # <http://github.com/ActiveState/code/blob/master/recipes/Python/
7 # 546530_Size_of_Python_objects_revised/recipe-546530.py>,
8 # <http://code.activestate.com/recipes/546530-size-of-python-objects-revised>
9 # and <http://code.activestate.com/recipes/544288-size-of-python-objects>.
11 # Recent versions of this module handle objects like ``namedtuples``,
12 # ``closure``, and NumPy data ``arange``, ``array``, ``matrix``, etc.
14 # See also project Pympler at <https://github.com/pympler/pympler> and
15 # memory footprint recipe <http://code.activestate.com/recipes/577504/>.
17 # Tested with 64-bit Python 2.6.9 (and numpy 1.6.2), 2.7.13 (and numpy
18 # 1.13.1), 3.5.3 and 3.6.2 on macOS 10.12.6 Sierra, with 64-bit Intel-
19 # Python 3.5.3 (and numpy 1.11.3) on macOS 10.12.6 Sierra and with
20 # Pythonista 3.1 using 64-bit Python 2.7.12 and 3.5.1 (both with numpy
21 # 1.8.0) on iOS 10.3.3.
23 # Earlier versions of this module were tested with 32-bit Python 2.2.3,
24 # 2.3.7, 2.4.5, 2.5.1, 2.5.2, 2.6.2, 3.0.1 or 3.1a2 on CentOS 4.6, SuSE
25 # 9.3, MacOS X 10.3.9 Panther (PPC), MacOS X 10.4.11 Tiger, Solaris 10
26 # (Opteron) and Windows XP, with 64-bit Python 3.0.1 on RHEL 3u7 and
27 # Solaris 10 (Opteron) and with 64-bit Python 2.7.10 and 3.5.1 on MacOS
28 # X 10.11.5 El Capitan (all without numpy).
30 # This module was checked statically with PyChecker 0.8.12, PyFlakes
31 # 1.5.0, PyCodeStyle 2.3.1 (formerly Pep8) and McCabe 0.6.1 using Python
32 # 2.7.13 and with Flake8 3.3.0 using Python 3.6.2, all thru this post-
33 # processor <http://code.activestate.com/recipes/546532/>
36 This module exposes 9 functions and 2 classes to obtain lengths (in
37 items) and sizes (in bytes) of Python objects for Python 2.6 and later,
38 including Python 3+ [#v]_.
40 **Public Functions** [#unsafe]_
42 Function **asizeof** calculates the combined (approximate) size
43 in bytes of one or several Python objects.
45 Function **asizesof** returns a tuple containing the (approximate)
46 size in bytes for each given Python object separately.
48 Function **asized** returns for each object an instance of class
49 **Asized** containing all the size information of the object and
50 a tuple with the referents [#refs]_.
52 Functions **basicsize** and **itemsize** return the *basic*
53 respectively *itesize* of the given object, both in bytes. For
54 objects as ``array.array``, ``numpy.array``, ``numpy.matrix``,
55 etc. where the item size varies depending on the instance-specific
56 data type, function **itemsize** returns that item size.
58 Function **flatsize** returns the *flat size* of a Python object
59 in bytes defined as the *basic size* plus the *item size* times
60 the *length* of the given object.
62 Function **alen** [#alen]_ returns the *length* of an object like
63 standard function ``len`` but extended for several types. E.g.
64 the **alen** of a multi-precision int (or long) is the number of
65 ``digits`` [#digit]_. The *length* of most *mutable* sequence
66 objects includes an estimate of the over-allocation and therefore,
67 the **alen** value may differ from the standard ``len`` result.
68 For objects like ``array.array``, ``numpy.array``, ``numpy.matrix``,
69 etc. function **alen** returns the proper number of items.
71 Function **refs** returns (a generator for) the referents [#refs]_
74 Certain classes are known to be sub-classes of or to behave as
75 ``dict`` objects. Function **adict** can be used to install
76 other class objects to be treated like ``dict``.
78 **Public Classes** [#unsafe]_
80 Class **Asizer** may be used to accumulate the results of several
81 sizing calls. After creating an **Asizer** instance, use methods
82 **asizeof** and **asizesof** as needed to size any number of
83 additional objects and accumulate the sizes.
85 Call methods **exclude_refs** and/or **exclude_types** to exclude
86 references to respectively instances or types of certain objects.
88 Use one of the **print\_...** methods to report the statistics.
90 An instance of class **Asized** is returned for each object sized
91 with the **asized** function or method.
95 Any duplicate, given objects are sized only once and the size
96 is included in the combined total only once. But functions
97 **asizesof** and **asized** will return a size value respectively
98 an **Asized** instance for each given object, including duplicates.
100 **Definitions** [#arb]_
102 The *length* of an objects like ``dict``, ``list``, ``set``,
103 ``str``, ``tuple``, etc. is defined as the number of items held
104 in or allocated by the object. Held items are *references* to
105 other objects, called the *referents*.
107 The *size* of an object is defined as the sum of the *flat size*
108 of the object plus the sizes of any referents [#refs]_. Referents
109 are visited recursively up to the specified detail level. However,
110 the size of objects referenced multiple times is included only once
113 The *flat size* of an object is defined as the *basic size* of the
114 object plus the *item size* times the number of allocated *items*,
115 *references* to referents. The *flat size* does include the size
116 for the *references* to the referents, but not the size of the
117 referents themselves.
119 The *flat size* returned by function *flatsize* equals the result
120 of function *asizeof* with options *code=True*, *ignored=False*,
121 *limit=0* and option *align* set to the same value.
123 The accurate *flat size* for an object is obtained from function
124 ``sys.getsizeof()`` where available. Otherwise, the *length* and
125 *size* of sequence objects as ``dicts``, ``lists``, ``sets``, etc.
126 is based on an estimate for the number of allocated items. As a
127 result, the reported *length* and *size* may differ substantially
128 from the actual *length* and *size*.
130 The *basic* and *item size* are obtained from the ``__basicsize__``
131 respectively ``__itemsize__`` attributes of the (type of the)
132 object. Where necessary (e.g. sequence objects), a zero
133 ``__itemsize__`` is replaced by the size of a corresponding C type.
135 The overhead for Python's garbage collector (GC) is included in
136 the *basic size* of (GC managed) objects as well as the space
137 needed for ``refcounts`` (used only in certain Python builds).
139 Optionally, size values can be aligned to any power of 2 multiple.
141 **Size of (byte)code**
143 The *(byte)code size* of objects like classes, functions, methods,
144 modules, etc. can be included by setting option *code=True*.
146 Iterators are handled like sequences: iterated object(s) are
147 sized like *referents* [#refs]_ but only up to the specified level
148 or recursion *limit* (and only if function ``gc.get_referents()``
149 returns the referent object of iterators).
151 Generators are sized as *(byte)code* only, but the generated objects
154 **Old- and New-style Classes**
156 All old- and new-style ``class``, instance and ``type`` objects,
157 are handled uniformly such that (a) instance objects are distinguished
158 from class objects and (b) instances of different old-style classes
159 can be dealt with separately.
161 Class and type objects are represented as ``<class ....* def>``
162 respectively ``<type ... def>`` where the ``*`` indicates an old-style
163 class and the ``... def`` suffix marks the *definition object*.
164 Instances of classes are shown as ``<class module.name*>`` without
165 the ``... def`` suffix. The ``*`` after the name indicates an
166 instance of an old-style class.
170 To avoid excessive sizes, several object types are ignored [#arb]_
171 by default, e.g. built-in functions, built-in types and classes
172 [#bi]_, function globals and module referents. However, any
173 instances thereof and module objects will be sized when passed as
174 given objects. Ignored object types are included unless option
175 *ignored* is set accordingly.
177 In addition, many ``__...__`` attributes of callable objects are
178 ignored [#arb]_, except crucial ones, e.g. class attributes ``__dict__``,
179 ``__doc__``, ``__name__`` and ``__slots__``. For more details, see
180 the type-specific ``_..._refs()`` and ``_len_...()`` functions below.
182 .. rubric:: Footnotes
183 .. [#unsafe] The functions and classes in this module are not thread-safe.
185 .. [#v] Earlier editions of this module supported Python versions down
186 to Python 2.2. To use Python 2.5 or older, try module ``asizeof``
187 from project `Pympler 0.3.x <https://github.com/pympler/pympler>`_.
189 .. [#alen] Former function *leng*, class attribute *leng* and keyword
190 argument *leng* have all been renamed to *alen*. However, function
191 *leng* is still available for backward compatibility.
193 .. [#refs] The *referents* of an object are the objects referenced *by*
194 that object. For example, the *referents* of a ``list`` are the
195 objects held in the ``list``, the *referents* of a ``dict`` are
196 the key and value objects in the ``dict``, etc.
198 .. [#arb] These definitions and other assumptions are rather arbitrary
199 and may need corrections or adjustments.
201 .. [#digit] See Python source file ``.../Include/longinterp.h`` for the
202 C ``typedef`` of ``digit`` used in multi-precision int (or long)
203 objects. The C ``sizeof(digit)`` in bytes can be obtained in
204 Python from the int (or long) ``__itemsize__`` attribute.
205 Function **alen** determines the number of ``digits`` of an int
208 .. [#bi] ``Type``s and ``class``es are considered built-in if the
209 ``__module__`` of the type or class is listed in the private
210 ``_builtin_modules``.
213 if sys
.version_info
< (2, 6, 0):
214 raise NotImplementedError('%s requires Python 2.6 or newer' % ('asizeof',))
216 from inspect
import (isbuiltin
, isclass
, iscode
, isframe
, isfunction
,
217 ismethod
, ismodule
, stack
)
219 from os
import curdir
, linesep
220 from struct
import calcsize
# type/class Struct only in Python 2.5+
221 import types
as Types
223 import weakref
as Weakref
225 __all__
= ['adict', 'asized', 'asizeof', 'asizesof',
226 'Asized', 'Asizer', # classes
227 'basicsize', 'flatsize', 'itemsize', 'alen', 'refs']
228 __version__
= '17.08.24'
230 # any classes or types in modules listed in _builtin_modules are
231 # considered built-in and ignored by default, as built-in functions
232 if __name__
== '__main__':
233 _builtin_modules
= (int.__module
__, 'types', Exception.__module
__) # , 'weakref'
234 else: # treat this very module as built-in
235 _builtin_modules
= (int.__module
__, 'types', Exception.__module
__, __name__
) # , 'weakref'
237 # sizes of some primitive C types
238 # XXX len(pack(T, 0)) == Struct(T).size == calcsize(T)
239 _sizeof_Cbyte
= calcsize('c') # sizeof(unsigned char)
240 _sizeof_Clong
= calcsize('l') # sizeof(long)
241 _sizeof_Cvoidp
= calcsize('P') # sizeof(void*)
243 # sizeof(long) != sizeof(ssize_t) on LLP64
244 if _sizeof_Clong
< _sizeof_Cvoidp
: # pragma: no coverage
251 '''Like struct.calcsize() but handling 'z' for Py_ssize_t.
253 return calcsize(fmt
.replace('z', _z_P_L
))
256 # defaults for some basic sizes with 'z' for C Py_ssize_t
257 _sizeof_CPyCodeObject
= _calcsize('Pz10P5i0P') # sizeof(PyCodeObject)
258 _sizeof_CPyFrameObject
= _calcsize('Pzz13P63i0P') # sizeof(PyFrameObject)
259 _sizeof_CPyModuleObject
= _calcsize('PzP0P') # sizeof(PyModuleObject)
261 # defaults for some item sizes with 'z' for C Py_ssize_t
262 _sizeof_CPyDictEntry
= _calcsize('z2P') # sizeof(PyDictEntry)
263 _sizeof_Csetentry
= _calcsize('lP') # sizeof(setentry)
265 try: # C typedef digit for multi-precision int (or long)
266 _sizeof_Cdigit
= long.__itemsize
__
267 except NameError: # no long in Python 3.0
268 _sizeof_Cdigit
= int.__itemsize
__
269 if _sizeof_Cdigit
< 2: # pragma: no coverage
270 raise AssertionError('sizeof(%s) bad: %d' % ('digit', _sizeof_Cdigit
))
272 # Get character size for internal unicode representation in Python < 3.3
273 try: # sizeof(unicode_char)
275 except NameError: # no unicode() in Python 3.0
277 u
= u
.encode('unicode-internal') # see .../Lib/test/test_sys.py
278 _sizeof_Cunicode
= len(u
)
281 try: # size of GC header, sizeof(PyGC_Head)
282 import _testcapi
as t
283 _sizeof_CPyGC_Head
= t
.SIZEOF_PYGC_HEAD
# new in Python 2.6
284 except (ImportError, AttributeError): # sizeof(PyGC_Head)
285 # alignment should be to sizeof(long double) but there
286 # is no way to obtain that value, assume twice double
287 t
= calcsize('2d') - 1
288 _sizeof_CPyGC_Head
= (_calcsize('2Pz') + t
) & ~t
291 # size of refcounts (Python debug build only)
292 if hasattr(sys
, 'gettotalrefcount'): # pragma: no coverage
293 _sizeof_Crefcounts
= _calcsize('2z')
295 _sizeof_Crefcounts
= 0
298 from abc
import ABCMeta
303 # some flags from .../Include/object.h
304 _Py_TPFLAGS_HEAPTYPE
= 1 << 9 # Py_TPFLAGS_HEAPTYPE
305 _Py_TPFLAGS_HAVE_GC
= 1 << 14 # Py_TPFLAGS_HAVE_GC
307 _Type_type
= type(type) # == type and new-style class type
310 # compatibility functions for more uniform
311 # behavior across Python version 2.2 thu 3.0
313 def _items(obj
): # dict only
314 '''Return iter-/generator, preferably.
316 return getattr(obj
, 'iteritems', obj
.items
)()
319 def _keys(obj
): # dict only
320 '''Return iter-/generator, preferably.
322 return getattr(obj
, 'iterkeys', obj
.keys
)()
325 def _values(obj
): # dict only
326 '''Return iter-/generator, preferably.
328 return getattr(obj
, 'itervalues', obj
.values
)()
331 try: # callable() builtin
332 _iscallable
= callable
333 except NameError: # callable() removed in Python 3.0
334 def _iscallable(obj
):
335 '''Substitute for callable().'''
336 return hasattr(obj
, '__call__')
338 # 'cell' is holding data used in closures
339 c
= (lambda unused
: (lambda: unused
))(None)
341 _cell_type
= type(c
.__closure
__[0])
342 except AttributeError: # Python 2.5
343 _cell_type
= type(c
.func_closure
[0])
347 from gc
import get_objects
as _getobjects
# containers only?
350 # modules first, globals and stack
351 # objects (may contain duplicates)
352 return tuple(_values(sys
.modules
)) + (
353 globals(), stack(sys
.getrecursionlimit())[2:])
355 try: # only used to get referents of
356 # iterators, but gc.get_referents()
357 # returns () for dict...-iterators
358 from gc
import get_referents
as _getreferents
360 def _getreferents(unused
):
361 return () # sorry, no refs
363 # sys.getsizeof() new in Python 2.6, adjusted below
364 _getsizeof
= getattr(sys
, 'getsizeof', None)
368 except NameError: # no intern() in Python 3.0
375 def _basicsize(t
, base
=0, heap
=False, obj
=None):
376 '''Get non-zero basicsize of type,
377 including the header sizes.
379 s
= max(getattr(t
, '__basicsize__', 0), base
)
380 # include gc header size
382 h
= getattr(t
, '__flags__', 0) & _Py_TPFLAGS_HAVE_GC
383 elif heap
: # type, allocated on heap
385 else: # None has no __flags__ attr
386 h
= getattr(obj
, '__flags__', 0) & _Py_TPFLAGS_HEAPTYPE
388 s
+= _sizeof_CPyGC_Head
389 # include reference counters
390 return s
+ _sizeof_Crefcounts
394 '''Cutoff as percentage.
396 return int((stats
- int(stats
)) * 100.0 + 0.5)
399 def _classof(obj
, dflt
=None):
400 '''Return the object's class object.
402 return getattr(obj
, '__class__', dflt
)
405 def _derive_typedef(typ
):
406 '''Return single, existing super type typedef or None.
408 v
= [v
for v
in _values(_typedefs
) if _issubclass(typ
, v
.type)]
414 def _dir2(obj
, pref
='', excl
=(), slots
=None, itor
=''):
415 '''Return an attribute name, object 2-tuple for certain
416 attributes or for the ``__slots__`` attributes of the
417 given object, but not both. Any iterator referent
418 objects are returned with the given name if the
421 if slots
: # __slots__ attrs
422 if hasattr(obj
, slots
):
423 # collect all inherited __slots__ attrs
424 # from list, tuple, or dict __slots__,
425 # while removing any duplicate attrs
427 for c
in type(obj
).mro():
428 for a
in getattr(c
, slots
, ()):
429 if a
.startswith('__'):
430 a
= '_' + c
.__name
__ + a
432 s
.setdefault(a
, getattr(obj
, a
))
433 # assume __slots__ tuple/list
434 # is holding the attr values
435 yield slots
, _Slots(s
) # _keys(s)
437 yield t
# attr name, value
438 elif itor
: # iterator referents
439 for o
in obj
: # iter(obj)
441 else: # regular attrs
443 if a
.startswith(pref
) and hasattr(obj
, a
) and a
not in excl
:
444 yield a
, getattr(obj
, a
)
447 def _infer_dict(obj
):
448 '''Return True for likely dict object via duck typing.
450 for ats
in (('__len__', 'get', 'has_key', 'items', 'keys', 'update', 'values'),
451 ('__len__', 'get', 'has_key', 'iteritems', 'iterkeys', 'itervalues')):
452 if all(_iscallable(getattr(obj
, a
, None)) for a
in ats
):
458 '''Return True if obj is a cell as used in a closure.
460 return isinstance(obj
, _cell_type
)
463 def _isdictclass(obj
):
464 '''Return True for known dict objects.
467 return c
and c
.__name
__ in _dict_classes
.get(c
.__module
__, ())
471 '''Return True for a stack frame object.
473 try: # safe isframe(), see pympler.muppy
475 except ReferenceError:
479 def _isnamedtuple(obj
):
480 '''Named tuples are identified via duck typing:
481 <http://www.gossamer-threads.com/lists/python/dev/1142178>
483 return isinstance(obj
, tuple) and hasattr(obj
, '_fields')
487 '''Prevent asizeof(all=True, ...) crash.
489 Sizing gc.get_objects() crashes in Pythonista3 with
490 Python 3.5.1 on iOS due to 1-tuple (<Null>,) object.
492 return isinstance(obj
, tuple) and len(obj
) == 1 \
493 and repr(obj
) == '(<NULL>,)'
497 '''Return True for a NumPy arange, array, matrix, etc. instance.
499 if _numpy_types
: # see also _len_numpy
500 return isinstance(obj
, _numpy_types
) or \
501 (_moduleof(_classof(obj
)).startswith('numpy') and
502 hasattr(obj
, 'nbytes'))
506 def _issubclass(sub
, sup
):
507 '''Safe issubclass().
509 if sup
is not object:
511 return issubclass(sub
, sup
)
517 def _itemsize(t
, item
=0):
518 '''Get non-zero itemsize of type.
520 # replace zero value with default
521 return getattr(t
, '__itemsize__', 0) or item
525 '''Keyword arguments as a string.
527 return ', '.join(sorted('%s=%r' % kv
for kv
in _items(kwds
)))
531 '''Object length as a string.
534 if n
is None: # no len
536 elif n
> _len(obj
): # extended
543 def _moduleof(obj
, dflt
=''):
544 '''Return the object's module name.
546 return getattr(obj
, '__module__', dflt
)
549 def _nameof(obj
, dflt
=''):
550 '''Return the name of an object.
552 return getattr(obj
, '__name__', dflt
)
555 def _objs_opts(objs
, all
=None, **opts
):
556 '''Return given or 'all' objects
557 and the remaining options.
559 if objs
: # given objects
561 elif all
in (False, None):
563 elif all
is True: # 'all' objects
564 t
= tuple(_getobjects())
565 if sys
.platform
== 'ios':
566 # remove any tuples containing NULLs
567 t
= tuple(o
for o
in t
if not _isNULL(o
))
569 raise ValueError('invalid option: %s=%r' % ('all', all
))
573 def _p100(part
, total
, prec
=1):
574 '''Return percentage as string.
579 return '%.*f%%' % (prec
, r
)
584 '''Return 's' if plural.
594 '''Finds the next power of 2.
602 def _prepr(obj
, clip
=0):
603 '''Prettify and clip long repr() string.
605 return _repr(obj
, clip
=clip
).strip('<>').replace("'", '') # remove <''>
608 def _printf(fmt
, *args
, **print3opts
):
609 '''Formatted print to sys.stdout or given stream.
611 *print3opts* -- print keyword arguments, like Python 3.+
613 if print3opts
: # like Python 3.0
614 f
= print3opts
.get('file', None) or sys
.stdout
619 f
.write(print3opts
.get('end', linesep
))
620 if print3opts
.get('flush', False):
628 def _refs(obj
, named
, *attrs
, **kwds
):
629 '''Return specific attribute objects of an object.
637 for a
in attrs
: # cf. inspect.getmembers()
639 yield _N(a
, getattr(obj
, a
))
640 if kwds
: # kwds are _dir2() args
641 for a
, o
in _dir2(obj
, **kwds
):
645 def _repr(obj
, clip
=80):
646 '''Clips long repr() string.
652 if 0 < clip
< len(r
):
655 r
= r
[:h
] + '....' + r
[-h
:]
659 def _SI(size
, K
=1024, i
='i'):
660 '''Return size as SI string.
664 for si
in iter('KMGPTE'):
667 return ' or %.1f %s%sB' % (f
, si
, i
)
671 def _SI2(size
, **kwds
):
672 '''Return size as regular plus SI string.
674 return str(size
) + _SI(size
, **kwds
)
677 # type-specific referents functions
679 def _cell_refs(obj
, named
):
680 return _refs(obj
, named
, 'cell_contents')
683 def _class_refs(obj
, named
):
684 '''Return specific referents of a class object.
686 return _refs(obj
, named
, '__class__', '__dict__', '__doc__', '__mro__',
687 '__name__', '__slots__', '__weakref__')
690 def _co_refs(obj
, named
):
691 '''Return specific referents of a code object.
693 return _refs(obj
, named
, pref
='co_')
696 def _dict_refs(obj
, named
):
697 '''Return key and value objects of a dict/proxy.
701 for k
, v
in _items(obj
):
703 yield _NamedRef('[K] ' + s
, k
)
704 yield _NamedRef('[V] ' + s
+ ': ' + _repr(v
), v
)
706 for k
, v
in _items(obj
):
709 except ReferenceError:
710 warnings
.warn("Reference error iterating '%s'" % (_classof(obj
),))
713 def _enum_refs(obj
, named
):
714 '''Return specific referents of an enumerate object.
716 return _refs(obj
, named
, '__doc__')
719 def _exc_refs(obj
, named
):
720 '''Return specific referents of an Exception object.
722 # .message raises DeprecationWarning in Python 2.6
723 return _refs(obj
, named
, 'args', 'filename', 'lineno', 'msg', 'text') # , 'message', 'mixed'
726 def _file_refs(obj
, named
):
727 '''Return specific referents of a file object.
729 return _refs(obj
, named
, 'mode', 'name')
732 def _frame_refs(obj
, named
):
733 '''Return specific referents of a frame object.
735 return _refs(obj
, named
, pref
='f_')
738 def _func_refs(obj
, named
):
739 '''Return specific referents of a function or lambda object.
741 return _refs(obj
, named
, '__doc__', '__name__', '__code__', '__closure__',
742 pref
='func_', excl
=('func_globals',))
745 def _gen_refs(obj
, named
):
746 '''Return the referent(s) of a generator object.
748 # only some gi_frame attrs
749 f
= getattr(obj
, 'gi_frame', None)
750 return _refs(f
, named
, 'f_locals', 'f_code')
753 def _im_refs(obj
, named
):
754 '''Return specific referents of a method object.
756 return _refs(obj
, named
, '__doc__', '__name__', '__code__', pref
='im_')
759 def _inst_refs(obj
, named
):
760 '''Return specific referents of a class instance.
762 return _refs(obj
, named
, '__dict__', '__class__', slots
='__slots__')
765 def _iter_refs(obj
, named
):
766 '''Return the referent(s) of an iterator object.
768 r
= _getreferents(obj
) # special case
769 return _refs(r
, named
, itor
=_nameof(obj
) or 'iteref')
772 def _module_refs(obj
, named
):
773 '''Return specific referents of a module object.
775 # ignore this very module
776 if obj
.__name
__ == __name__
:
778 # module is essentially a dict
779 return _dict_refs(obj
.__dict
__, named
)
782 def _namedtuple_refs(obj
, named
):
783 '''Return specific referents of obj-as-sequence and slots but exclude dict.
785 for r
in _refs(obj
, named
, '__class__', slots
='__slots__'):
791 def _prop_refs(obj
, named
):
792 '''Return specific referents of a property object.
794 return _refs(obj
, named
, '__doc__', pref
='f')
797 def _seq_refs(obj
, unused
): # named unused for PyChecker
798 '''Return specific referents of a frozen/set, list, tuple and xrange object.
800 return obj
# XXX for r in obj: yield r
803 def _stat_refs(obj
, named
):
804 '''Return referents of a os.stat object.
806 return _refs(obj
, named
, pref
='st_')
809 def _statvfs_refs(obj
, named
):
810 '''Return referents of a os.statvfs object.
812 return _refs(obj
, named
, pref
='f_')
815 def _tb_refs(obj
, named
):
816 '''Return specific referents of a traceback object.
818 return _refs(obj
, named
, pref
='tb_')
821 def _type_refs(obj
, named
):
822 '''Return specific referents of a type object.
824 return _refs(obj
, named
, '__dict__', '__doc__', '__mro__',
825 '__name__', '__slots__', '__weakref__')
828 def _weak_refs(obj
, unused
): # named unused for PyChecker
829 '''Return weakly referent object.
831 try: # ignore 'key' of KeyedRef
833 except Exception: # XXX ReferenceError
837 _all_refs
= (None, _cell_refs
, _class_refs
, _co_refs
, _dict_refs
, _enum_refs
,
838 _exc_refs
, _file_refs
, _frame_refs
, _func_refs
, _gen_refs
,
839 _im_refs
, _inst_refs
, _iter_refs
, _module_refs
, _namedtuple_refs
,
840 _prop_refs
, _seq_refs
, _stat_refs
, _statvfs_refs
, _tb_refs
,
841 _type_refs
, _weak_refs
)
844 # type-specific length functions
851 except TypeError: # no len()
856 '''Array length (in bytes!).
858 return len(obj
) * obj
.itemsize
861 def _len_bytearray(obj
):
864 return obj
.__alloc
__()
867 def _len_code(obj
): # see .../Lib/test/test_sys.py
868 '''Length of code object (stack and variables only).
870 return (obj
.co_stacksize
+ obj
.co_nlocals
+
871 _len(obj
.co_freevars
) + _len(obj
.co_cellvars
) - 1)
875 '''Dict length in items (estimate).
877 n
= len(obj
) # active items
878 if n
< 6: # ma_smalltable ...
879 n
= 0 # ... in basicsize
880 else: # at least one unused
886 '''Length of a frame object.
888 c
= getattr(obj
, 'f_code', None)
896 _digit2p2
= 1 << (_sizeof_Cdigit
<< 3)
897 _digitmax
= _digit2p2
- 1 # == (2 * PyLong_MASK + 1)
898 _digitlog
= 1.0 / log(_digit2p2
)
902 '''Length of multi-precision int (aka long) in digits.
907 # no log(x[, base]) in Python 2.2
908 n
+= int(log(i
) * _digitlog
)
915 '''Length (hint) of an iterator.
917 n
= getattr(obj
, '__length_hint__', None)
926 '''Length of list (estimate).
929 # estimate over-allocation
937 def _len_module(obj
):
940 return _len(obj
.__dict
__) # _len(dir(obj))
944 '''NumPy array, matrix, etc. length (in bytes!).
946 return obj
.nbytes
# == obj.size * obj.itemsize
950 '''Length of frozen/set (estimate).
953 if n
> 8: # assume half filled
954 n
= _power2(n
+ n
- 2)
964 return ((obj
.stop
- obj
.start
+ 1) // obj
.step
)
965 except (AttributeError, TypeError):
975 def _len_struct(obj
):
976 '''Struct length in bytes.
980 except AttributeError:
984 def _len_unicode(obj
):
990 _all_lens
= (None, _len
, _len_array
, _len_bytearray
, _len_code
,
991 _len_dict
, _len_frame
, _len_int
, _len_iter
,
992 _len_list
, _len_module
, _len_numpy
, _len_set
,
993 _len_slice
, _len_slots
, _len_struct
, _len_unicode
)
995 # more private functions and classes
997 _old_style
= '*' # marker
998 _new_style
= '' # no marker
1001 class _Claskey(object):
1002 '''Wrapper for class objects.
1004 __slots__
= ('_obj', '_sty')
1006 def __init__(self
, obj
, style
):
1007 self
._obj
= obj
# XXX Weakref.ref(obj)
1013 r
= '%s%s def>' % (r
[:-1], self
._sty
)
1014 elif self
._sty
is _old_style
and not r
.startswith('class '):
1015 r
= 'class %s%s def' % (r
, self
._sty
)
1017 r
= '%s%s def' % (r
, self
._sty
)
1022 # For most objects, the object type is used as the key in the
1023 # _typedefs dict further below, except class and type objects
1024 # and old-style instances. Those are wrapped with separate
1025 # _Claskey or _Instkey instances to be able (1) to distinguish
1026 # instances of different old-style classes by class, (2) to
1027 # distinguish class (and type) instances from class (and type)
1028 # definitions for new-style classes and (3) provide similar
1029 # results for repr() and str() of new- and old-style classes
1032 _claskeys
= {} # [id(obj)] = _Claskey()
1035 def _claskey(obj
, style
):
1036 '''Wraps an old- or new-style class object.
1039 k
= _claskeys
.get(i
, None)
1041 _claskeys
[i
] = k
= _Claskey(obj
, style
)
1046 # no Class- and InstanceType in Python 3.0
1047 _Types_ClassType
= Types
.ClassType
1048 _Types_InstanceType
= Types
.InstanceType
1050 class _Instkey(object):
1051 '''Wrapper for old-style class (instances).
1053 __slots__
= ('_obj',)
1055 def __init__(self
, obj
):
1056 self
._obj
= obj
# XXX Weakref.ref(obj)
1059 t
= _moduleof(self
._obj
), self
._obj
.__name
__, _old_style
1060 return '<class %s.%s%s>' % t
1063 _instkeys
= {} # [id(obj)] = _Instkey()
1066 '''Wraps an old-style class (instance).
1069 k
= _instkeys
.get(i
, None)
1071 _instkeys
[i
] = k
= _Instkey(obj
)
1075 '''Return class and instance keys for a class.
1078 if t
is _Types_InstanceType
:
1080 return _claskey(t
, _old_style
), _instkey(t
)
1081 elif t
is _Types_ClassType
:
1082 return _claskey(obj
, _old_style
), _instkey(obj
)
1083 elif t
is _Type_type
:
1084 return _claskey(obj
, _new_style
), obj
1085 return None, None # not a class
1088 '''Return the key for any object.
1091 if k
is _Types_InstanceType
:
1092 k
= _instkey(obj
.__class
__)
1093 elif k
is _Types_ClassType
:
1094 k
= _claskey(obj
, _old_style
)
1095 elif k
is _Type_type
:
1096 k
= _claskey(obj
, _new_style
)
1099 except AttributeError: # Python 3.0
1101 def _keytuple(obj
): # PYCHOK expected
1102 '''Return class and instance keys for a class.
1104 if type(obj
) is _Type_type
: # isclass(obj):
1105 return _claskey(obj
, _new_style
), obj
1106 return None, None # not a class
1108 def _objkey(obj
): # PYCHOK expected
1109 '''Return the key for any object.
1112 if k
is _Type_type
: # isclass(obj):
1113 k
= _claskey(obj
, _new_style
)
1117 class _NamedRef(object):
1118 '''Store referred object along
1119 with the name of the referent.
1121 __slots__
= ('name', 'ref')
1123 def __init__(self
, name
, ref
):
1128 class _Slots(tuple):
1129 '''Wrapper class for __slots__ attribute at
1130 class instances to account for the size
1131 of the __slots__ tuple/list containing
1132 references to the attribute values.
1137 # kinds of _Typedefs
1139 _all_kinds
= (_kind_static
, _kind_dynamic
, _kind_derived
, _kind_ignored
, _kind_inferred
) = (
1140 _i('static'), _i('dynamic'), _i('derived'), _i('ignored'), _i('inferred'))
1143 _Not_vari
= '' # non-variable item size
1146 class _Typedef(object):
1147 '''Type definition class.
1150 'base': 0, # basic size in bytes
1151 'item': 0, # item size in bytes
1152 'alen': None, # or _len_...() function
1153 'refs': None, # or _..._refs() function
1154 'both': None, # both data and code if True, code only if False
1155 'kind': None, # _kind_... value
1156 'type': None, # original type
1157 'vari': None} # item size attr name or _Not_vari
1159 def __init__(self
, **kwds
):
1162 def __lt__(self
, unused
): # for Python 3.0
1166 return repr(self
.args())
1169 t
= [str(self
.base
), str(self
.item
)]
1170 for f
in (self
.alen
, self
.refs
):
1172 t
.append(f
.__name
__)
1176 t
.append('(code only)')
1179 def args(self
): # as args tuple
1180 '''Return all attributes as arguments tuple.
1182 return (self
.base
, self
.item
, self
.alen
, self
.refs
,
1183 self
.both
, self
.kind
, self
.type)
1185 def dup(self
, other
=None, **kwds
):
1186 '''Duplicate attributes of dict or other typedef.
1189 d
= _dict_typedef
.kwds()
1195 def flat(self
, obj
, mask
=0):
1196 '''Return the aligned flat size.
1199 if self
.alen
and self
.item
> 0: # include items
1200 s
+= self
.alen(obj
) * self
.item
1201 if _getsizeof
: # _getsizeof prevails
1202 s
= _getsizeof(obj
, s
)
1204 s
= (s
+ mask
) & ~mask
1208 '''Return format dict.
1217 n
= ' (%s)' % _nameof(self
.alen
)
1218 return dict(base
=self
.base
, item
=i
, alen
=n
, code
=c
,
1222 '''Return all attributes as keywords dict.
1224 return dict(base
=self
.base
, item
=self
.item
,
1225 alen
=self
.alen
, refs
=self
.refs
,
1226 both
=self
.both
, kind
=self
.kind
,
1227 type=self
.type, vari
=self
.vari
)
1229 def save(self
, t
, base
=0, heap
=False):
1230 '''Saves this typedef plus its class typedef.
1233 if k
and k
not in _typedefs
: # instance key
1235 if c
and c
not in _typedefs
: # class key
1236 if t
.__module
__ in _builtin_modules
:
1237 k
= _kind_ignored
# default
1240 _typedefs
[c
] = _Typedef(base
=_basicsize(type(t
), base
=base
, heap
=heap
),
1242 both
=False, kind
=k
, type=t
)
1243 elif isbuiltin(t
) and t
not in _typedefs
: # array, range, xrange in Python 2.x
1244 _typedefs
[t
] = _Typedef(base
=_basicsize(t
, base
=base
),
1245 both
=False, kind
=_kind_ignored
, type=t
)
1247 raise KeyError('asizeof typedef %r bad: %r %r' % (self
, (c
, k
), self
.both
))
1249 def set(self
, safe_len
=False, **kwds
):
1250 '''Sets one or more attributes.
1252 if kwds
: # double check
1256 if safe_len
and self
.item
:
1259 def reset(self
, base
=0, item
=0, alen
=None, refs
=None,
1260 both
=True, kind
=None, type=None, vari
=_Not_vari
):
1261 '''Resets all specified attributes.
1264 raise ValueError('invalid option: %s=%r' % ('base', base
))
1268 raise ValueError('invalid option: %s=%r' % ('item', item
))
1271 if alen
in _all_lens
: # XXX or _iscallable(alen)
1274 raise ValueError('invalid option: %s=%r' % ('alen', alen
))
1275 if refs
in _all_refs
: # XXX or _iscallable(refs)
1278 raise ValueError('invalid option: %s=%r' % ('refs', refs
))
1279 if both
in (False, True):
1282 raise ValueError('invalid option: %s=%r' % ('both', both
))
1283 if kind
in _all_kinds
:
1286 raise ValueError('invalid option: %s=%r' % ('kind', kind
))
1288 self
.vari
= vari
or _Not_vari
1289 if str(self
.vari
) != self
.vari
:
1290 raise ValueError('invalid option: %s=%r' % ('vari', vari
))
1293 _typedefs
= {} # [key] = _Typedef()
1296 def _typedef_both(t
, base
=0, item
=0, alen
=None, refs
=None,
1297 kind
=_kind_static
, heap
=False, vari
=_Not_vari
):
1298 '''Adds new typedef for both data and code.
1300 v
= _Typedef(base
=_basicsize(t
, base
=base
), item
=_itemsize(t
, item
),
1301 refs
=refs
, alen
=alen
,
1302 both
=True, kind
=kind
, type=t
, vari
=vari
)
1303 v
.save(t
, base
=base
, heap
=heap
)
1304 return v
# for _dict_typedef
1307 def _typedef_code(t
, base
=0, refs
=None, kind
=_kind_static
, heap
=False):
1308 '''Adds new typedef for code only.
1310 v
= _Typedef(base
=_basicsize(t
, base
=base
),
1312 both
=False, kind
=kind
, type=t
)
1313 v
.save(t
, base
=base
, heap
=heap
)
1314 return v
# for _dict_typedef
1317 # static typedefs for data and code types
1318 _typedef_both(complex)
1319 _typedef_both(float)
1320 _typedef_both(list, refs
=_seq_refs
, alen
=_len_list
, item
=_sizeof_Cvoidp
) # sizeof(PyObject*)
1321 _typedef_both(tuple, refs
=_seq_refs
, alen
=_len
, item
=_sizeof_Cvoidp
) # sizeof(PyObject*)
1322 _typedef_both(property, refs
=_prop_refs
)
1323 _typedef_both(type(Ellipsis))
1324 _typedef_both(type(None))
1326 # _Slots is a special tuple, see _Slots.__doc__
1327 _typedef_both(_Slots
, item
=_sizeof_Cvoidp
,
1328 alen
=_len_slots
, # length less one
1329 refs
=None, # but no referents
1330 heap
=True) # plus head
1332 # dict, dictproxy, dict_proxy and other dict-like types
1333 _dict_typedef
= _typedef_both(dict, item
=_sizeof_CPyDictEntry
, alen
=_len_dict
, refs
=_dict_refs
)
1334 try: # <type dictproxy> only in Python 2.x
1335 _typedef_both(Types
.DictProxyType
, item
=_sizeof_CPyDictEntry
, alen
=_len_dict
, refs
=_dict_refs
)
1336 except AttributeError: # XXX any class __dict__ is <type dict_proxy> in Python 3.0?
1337 _typedef_both(type(_Typedef
.__dict
__), item
=_sizeof_CPyDictEntry
, alen
=_len_dict
, refs
=_dict_refs
)
1338 # other dict-like classes and types may be derived or inferred,
1339 # provided the module and class name is listed here (see functions
1340 # adict, _isdictclass and _infer_dict for further details)
1341 _dict_classes
= {'UserDict': ('IterableUserDict', 'UserDict'),
1342 'weakref': ('WeakKeyDictionary', 'WeakValueDictionary')}
1343 try: # <type module> is essentially a dict
1344 _typedef_both(Types
.ModuleType
, base
=_dict_typedef
.base
,
1345 item
=_dict_typedef
.item
+ _sizeof_CPyModuleObject
,
1346 alen
=_len_module
, refs
=_module_refs
)
1347 except AttributeError: # missing
1350 _getsizeof_excls
= () # to adjust _getsizeof
1353 def _getsizeof_excls_add(typ
):
1354 global _getsizeof_excls
1355 if typ
not in _getsizeof_excls
:
1356 _getsizeof_excls
+= (typ
,)
1359 # newer or obsolete types
1361 from array
import array
# array type
1363 def _array_kwds(obj
):
1364 if hasattr(obj
, 'itemsize'):
1368 # since item size varies by the array data type, set
1369 # itemsize to 1 byte and use _len_array in bytes; note,
1370 # function itemsize returns the actual size in bytes
1371 # and function alen returns the length in number of items
1372 return dict(alen
=_len_array
, item
=_sizeof_Cbyte
, vari
=v
)
1374 _typedef_both(array
, **_array_kwds(array('d', [])))
1376 v
= sys
.version_info
1377 _array_excl
= (v
[0] == 2 and v
< (2, 7, 4)) or \
1378 (v
[0] == 3 and v
< (3, 2, 4))
1379 if _array_excl
: # see function _typedef below
1380 _getsizeof_excls_add(array
)
1383 except ImportError: # missing
1384 _array_excl
= array
= None # see function _typedef below
1386 try: # bool has non-zero __itemsize__ in 3.0
1388 except NameError: # missing
1391 try: # ignore basestring
1392 _typedef_both(basestring
, alen
=None)
1393 except NameError: # missing
1397 if isbuiltin(buffer): # Python 2.2
1398 _typedef_both(type(buffer('')), item
=_sizeof_Cbyte
, alen
=_len
) # XXX len in bytes?
1400 _typedef_both(buffer, item
=_sizeof_Cbyte
, alen
=_len
) # XXX len in bytes?
1401 except NameError: # missing
1405 _typedef_both(bytearray
, item
=_sizeof_Cbyte
, alen
=_len_bytearray
)
1406 except NameError: # bytearray new in 2.6, 3.0
1409 if type(bytes
) is not type(str): # bytes is str in 2.6, bytes new in 2.6, 3.0
1410 _typedef_both(bytes
, item
=_sizeof_Cbyte
, alen
=_len
) # bytes new in 2.6, 3.0
1411 except NameError: # missing
1413 try: # XXX like bytes
1414 _typedef_both(str8
, item
=_sizeof_Cbyte
, alen
=_len
) # PYCHOK str8 new in 2.6, 3.0
1415 except NameError: # missing
1419 _typedef_both(enumerate, refs
=_enum_refs
)
1420 except NameError: # missing
1423 try: # Exception is type in Python 3.0
1424 _typedef_both(Exception, refs
=_exc_refs
)
1425 except Exception: # missing
1429 _typedef_both(file, refs
=_file_refs
)
1430 except NameError: # missing
1434 _typedef_both(frozenset, item
=_sizeof_Csetentry
, alen
=_len_set
, refs
=_seq_refs
)
1435 except NameError: # missing
1438 _typedef_both(set, item
=_sizeof_Csetentry
, alen
=_len_set
, refs
=_seq_refs
)
1439 except NameError: # missing
1442 try: # not callable()
1443 _typedef_both(Types
.GetSetDescriptorType
)
1444 except AttributeError: # missing
1447 try: # if long exists, it is multi-precision ...
1448 _typedef_both(long, item
=_sizeof_Cdigit
, alen
=_len_int
)
1449 _typedef_both(int) # ... and int is fixed size
1450 except NameError: # no long, only multi-precision int in Python 3.0
1451 _typedef_both(int, item
=_sizeof_Cdigit
, alen
=_len_int
)
1453 try: # not callable()
1454 _typedef_both(Types
.MemberDescriptorType
)
1455 except AttributeError: # missing
1459 _typedef_both(type(NotImplemented)) # == Types.NotImplementedType
1460 except NameError: # missing
1465 import numpy
# NumPy array, matrix, etc.
1467 def _numpy_kwds(obj
):
1469 b
= _getsizeof(obj
, 96) - obj
.nbytes
1471 b
= 96 # 96..144 typical __basicsize__?
1472 # since item size depends on the nympy data type, set
1473 # itemsize to 1 byte and use _len_numpy in bytes; note,
1474 # function itemsize returns the actual size in bytes,
1475 # function alen returns the length in number of items
1476 return dict(base
=b
, item
=_sizeof_Cbyte
, # not obj.itemsize
1480 for d
in (numpy
.array(range(0)), numpy
.arange(0),
1481 numpy
.matrix(range(0)), numpy
.ma
.masked_array([])):
1483 if t
not in _numpy_types
:
1484 _numpy_types
+= (t
,)
1485 if _isnumpy(d
): # double check
1486 _typedef_both(t
, **_numpy_kwds(d
))
1488 raise AssertionError('not %s: %r' % ('numpy', d
))
1490 # sizing numpy 1.13 arrays works fine, but 1.8 and older
1491 # appears to suffer from sys.getsizeof() bug like array
1492 v
= tuple(map(int, numpy
.__version
__.split('.')))
1493 _numpy_excl
= v
< (1, 9, 0)
1494 if _numpy_excl
: # see function _typedef below
1495 for t
in _numpy_types
:
1496 _getsizeof_excls_add(t
)
1500 _numpy_excl
= False # see function _typedef below
1503 _typedef_both(range)
1504 except NameError: # missing
1507 _typedef_both(xrange)
1508 except NameError: # missing
1512 _typedef_both(reversed, refs
=_enum_refs
)
1513 except NameError: # missing
1517 _typedef_both(slice, item
=_sizeof_Cvoidp
, alen
=_len_slice
) # XXX worst-case itemsize?
1518 except NameError: # missing
1523 _typedef_both(type(stat(curdir
)), refs
=_stat_refs
) # stat_result
1524 except ImportError: # missing
1528 from os
import statvfs
1529 _typedef_both(type(statvfs(curdir
)), refs
=_statvfs_refs
, # statvfs_result
1530 item
=_sizeof_Cvoidp
, alen
=_len
)
1531 except ImportError: # missing
1535 from struct
import Struct
# only in Python 2.5 and 3.0
1536 _typedef_both(Struct
, item
=_sizeof_Cbyte
, alen
=_len_struct
) # len in bytes
1537 except ImportError: # missing
1541 _typedef_both(Types
.TracebackType
, refs
=_tb_refs
)
1542 except AttributeError: # missing
1546 _typedef_both(unicode, alen
=_len_unicode
, item
=_sizeof_Cunicode
)
1547 _typedef_both(str, alen
=_len
, item
=_sizeof_Cbyte
) # 1-byte char
1548 except NameError: # str is unicode
1549 _typedef_both(str, alen
=_len_unicode
, item
=_sizeof_Cunicode
)
1551 try: # <type 'KeyedRef'>
1552 _typedef_both(Weakref
.KeyedRef
, refs
=_weak_refs
, heap
=True) # plus head
1553 except AttributeError: # missing
1556 try: # <type 'weakproxy'>
1557 _typedef_both(Weakref
.ProxyType
)
1558 except AttributeError: # missing
1561 try: # <type 'weakref'>
1562 _typedef_both(Weakref
.ReferenceType
, refs
=_weak_refs
)
1563 except AttributeError: # missing
1566 # some other, callable types
1567 _typedef_code(object, kind
=_kind_ignored
)
1568 _typedef_code(super, kind
=_kind_ignored
)
1569 _typedef_code(_Type_type
, kind
=_kind_ignored
)
1572 _typedef_code(classmethod, refs
=_im_refs
)
1576 _typedef_code(staticmethod, refs
=_im_refs
)
1580 _typedef_code(Types
.MethodType
, refs
=_im_refs
)
1584 try: # generator, code only, no len(), not callable()
1585 _typedef_code(Types
.GeneratorType
, refs
=_gen_refs
)
1586 except AttributeError: # missing
1589 try: # <type 'weakcallableproxy'>
1590 _typedef_code(Weakref
.CallableProxyType
, refs
=_weak_refs
)
1591 except AttributeError: # missing
1594 # any type-specific iterators
1595 s
= [_items({}), _keys({}), _values({})]
1596 try: # reversed list and tuples iterators
1597 s
.extend([reversed([]), reversed(())])
1598 except NameError: # missing
1601 try: # range iterator
1603 except NameError: # missing
1606 try: # callable-iterator
1607 from re
import finditer
1608 s
.append(finditer('', ''))
1609 except ImportError: # missing
1612 for t
in _values(_typedefs
):
1613 if t
.type and t
.alen
:
1614 try: # create an (empty) instance
1621 _typedef_both(type(i
), alen
=_len_iter
, refs
=_iter_refs
, item
=0) # no itemsize!
1622 except (KeyError, TypeError): # ignore non-iterables, duplicates, etc.
1627 if _getsizeof_excls
and _getsizeof
:
1628 # workaround the sys.getsizeof (and numpy?) bug
1629 def _wraps(sys_sizeof
):
1630 def _getsizeof_wrap(obj
, *default
):
1631 if isinstance(obj
, _getsizeof_excls
):
1635 raise TypeError('no default')
1637 return sys_sizeof(obj
, *default
)
1638 return _getsizeof_wrap
1640 _getsizeof
= _wraps(_getsizeof
)
1644 def _typedef(obj
, derive
=False, infer
=False): # MCCABE 24
1645 '''Creates a new typedef for an object.
1648 v
= _Typedef(base
=_basicsize(t
, obj
=obj
),
1649 kind
=_kind_dynamic
, type=t
)
1650 # _printf('new %r %r/%r %s', t, _basicsize(t), _itemsize(t), _repr(dir(obj)))
1651 if ismodule(obj
): # handle module like dict
1652 v
.dup(item
=_dict_typedef
.item
+ _sizeof_CPyModuleObject
,
1656 v
.set(base
=_basicsize(t
, base
=_sizeof_CPyFrameObject
, obj
=obj
),
1661 v
.set(base
=_basicsize(t
, base
=_sizeof_CPyCodeObject
, obj
=obj
),
1662 item
=_sizeof_Cvoidp
,
1665 both
=False) # code only
1666 elif _iscallable(obj
):
1667 if isclass(obj
): # class or type
1668 v
.set(refs
=_class_refs
,
1669 both
=False) # code only
1670 if _moduleof(obj
) in _builtin_modules
:
1671 v
.set(kind
=_kind_ignored
)
1672 elif isbuiltin(obj
): # function or method
1673 v
.set(both
=False, # code only
1675 elif isfunction(obj
):
1676 v
.set(refs
=_func_refs
,
1677 both
=False) # code only
1679 v
.set(refs
=_im_refs
,
1680 both
=False) # code only
1681 elif isclass(t
): # callable instance, e.g. SCons,
1682 # handle like any other instance further below
1683 v
.set(item
=_itemsize(t
), safe_len
=True,
1684 refs
=_inst_refs
) # not code only!
1686 v
.set(both
=False) # code only
1687 elif _issubclass(t
, dict):
1688 v
.dup(kind
=_kind_derived
)
1689 elif _isdictclass(obj
) or (infer
and _infer_dict(obj
)):
1690 v
.dup(kind
=_kind_inferred
)
1692 v
.set(item
=_itemsize(t
), refs
=_cell_refs
)
1693 elif _isnamedtuple(obj
):
1694 v
.set(refs
=_namedtuple_refs
)
1695 elif _isnumpy(obj
): # NumPy data
1696 v
.set(**_numpy_kwds(obj
))
1698 _getsizeof_excls_add(t
)
1699 elif array
and isinstance(obj
, array
):
1700 v
.set(**_array_kwds(obj
))
1702 _getsizeof_excls_add(t
)
1703 elif _moduleof(obj
) in _builtin_modules
:
1704 v
.set(kind
=_kind_ignored
)
1705 else: # assume an instance of some class
1707 p
= _derive_typedef(t
)
1708 if p
: # duplicate parent
1709 v
.dup(other
=p
, kind
=_kind_derived
)
1711 if _issubclass(t
, Exception):
1712 v
.set(item
=_itemsize(t
), safe_len
=True,
1715 elif isinstance(obj
, Exception):
1716 v
.set(item
=_itemsize(t
), safe_len
=True,
1719 v
.set(item
=_itemsize(t
), safe_len
=True,
1724 class _Prof(object):
1725 '''Internal type profile class.
1727 total
= 0 # total size
1728 high
= 0 # largest size
1729 number
= 0 # number of (unique) objects
1730 objref
= None # largest object (weakref)
1731 weak
= False # objref is weakref(object)
1733 def __cmp__(self
, other
):
1734 if self
.total
< other
.total
:
1736 if self
.total
> other
.total
:
1738 if self
.number
< other
.number
:
1740 if self
.number
> other
.number
:
1744 def __lt__(self
, other
): # for Python 3.0
1745 return self
.__cmp
__(other
) < 0
1747 def format(self
, clip
=0, grand
=None):
1748 '''Return format dict.
1750 if self
.number
> 1: # avg., plural
1751 a
, p
= int(self
.total
/ self
.number
), 's'
1753 a
, p
= self
.total
, ''
1755 if self
.weak
: # weakref'd
1757 t
= _SI2(self
.total
)
1759 t
+= ' (%s)' % _p100(self
.total
, grand
, prec
=0)
1760 return dict(avg
=_SI2(a
), high
=_SI2(self
.high
),
1761 lengstr
=_lengstr(o
), obj
=_repr(o
, clip
=clip
),
1764 def update(self
, obj
, size
):
1765 '''Updates this profile.
1769 if self
.high
< size
: # largest
1771 try: # prefer using weak ref
1772 self
.objref
, self
.weak
= Weakref
.ref(obj
), True
1774 self
.objref
, self
.weak
= obj
, False
1779 class Asized(object):
1780 '''Stores the results of an **asized** object in the following
1783 *size* -- total size of the object (including referents)
1785 *flat* -- flat size of the object
1787 *name* -- name or ``repr`` of the object
1789 *refs* -- tuple containing an **Asized** instance for each referent
1791 __slots__
= ('flat', 'name', 'refs', 'size')
1793 def __init__(self
, size
, flat
, refs
=(), name
=None):
1794 self
.size
= size
# total size
1795 self
.flat
= flat
# flat size
1796 self
.name
= name
# name, repr or None
1797 self
.refs
= tuple(refs
)
1800 return 'size %r, flat %r, refs[%d], name %r' % (
1801 self
.size
, self
.flat
, len(self
.refs
), self
.name
)
1803 def format(self
, format
='%(name)s size=%(size)d flat=%(flat)d',
1804 detail
=-1, order_by
='size', indent
=''):
1805 '''Formats the size information of the object and of all sized
1806 referents as a string.
1808 *format='%(name)s...'* -- specifies the format string per
1809 instance, valid interpolation parameters are 'name', 'size'
1812 *detail=-1* -- detail level up to which referents are
1813 printed (-1 for unlimited)
1815 *order_by='size'* -- sort order of referents, valid choices
1816 are 'name', 'size' or 'flat'
1818 *indent=''* -- optional indentation
1820 lines
= [indent
+ (format
% dict(size
=self
.size
, flat
=self
.flat
,
1822 if detail
and self
.refs
:
1823 refs
= sorted(self
.refs
, key
=lambda x
: getattr(x
, order_by
),
1824 reverse
=order_by
in ('size', 'flat'))
1825 lines
+= [ref
.format(format
=format
, detail
=detail
-1, order_by
=order_by
,
1826 indent
=indent
+' ') for ref
in refs
]
1827 return '\n'.join(lines
)
1829 def get(self
, name
, dflt
=None):
1830 '''Return the named referent (or *dflt* if not found).
1832 for ref
in self
.refs
:
1833 if name
== ref
.name
:
1838 class Asizer(object):
1839 '''State and options to accumulate sizes.
1845 _detail_
= 0 # for Asized only
1850 _cutoff
= 0 # in percent
1851 _depth
= 0 # deepest recursion
1854 _ign_d
= _kind_ignored
1855 _incl
= '' # or ' (incl. code)'
1856 _mask
= 7 # see _align_
1857 _missed
= 0 # due to errors
1861 _total
= 0 # total size
1863 _stream
= None # IO stream for printing
1865 def __init__(self
, **opts
):
1866 '''New **Asizer** accumulator.
1868 See this module documentation for more details. See method
1869 **reset** for all available options and defaults.
1874 def _printf(self
, fmt
, *args
, **print3opts
):
1875 '''Prints to sys.stdout or the configured stream if any is
1876 specified and if the file keyword argument is not already
1877 set in the **print3opts for this specific call.
1879 if self
._stream
and not print3opts
.get('file', None):
1882 _printf(fmt
, file=self
._stream
, **print3opts
)
1884 _printf(fmt
, *args
, **print3opts
)
1889 self
._depth
= 0 # recursion depth reached
1891 self
._incl
= '' # or ' (incl. code)'
1892 self
._missed
= 0 # due to errors
1893 self
._profile
= False
1896 self
._total
= 0 # total size
1897 for k
in _keys(self
._excl
_d
):
1900 def _nameof(self
, obj
):
1901 '''Return the object's name.
1903 return _nameof(obj
, '') or self
._repr
(obj
)
1905 def _prepr(self
, obj
):
1906 '''Like **prepr()**.
1908 return _prepr(obj
, clip
=self
._clip
_)
1910 def _prof(self
, key
):
1911 '''Get _Prof object.
1913 p
= self
._profs
.get(key
, None)
1915 self
._profs
[key
] = p
= _Prof()
1918 def _repr(self
, obj
):
1921 return _repr(obj
, clip
=self
._clip
_)
1923 def _sizer(self
, obj
, deep
, sized
): # MCCABE 16
1924 '''Sizes an object, recursively.
1926 s
, f
, i
= 0, 0, id(obj
)
1927 # skip obj if seen before
1928 # or if ref of a given obj
1933 s
= sized(s
, f
, name
=self
._nameof
(obj
))
1938 k
, rs
= _objkey(obj
), []
1939 if k
in self
._excl
_d
:
1940 self
._excl
_d
[k
] += 1
1942 v
= _typedefs
.get(k
, None)
1943 if not v
: # new typedef
1944 _typedefs
[k
] = v
= _typedef(obj
, derive
=self
._derive
_,
1946 if (v
.both
or self
._code
_) and v
.kind
is not self
._ign
_d
:
1947 s
= f
= v
.flat(obj
, self
._mask
) # flat size
1948 if self
._profile
: # profile type
1949 self
._prof
(k
).update(obj
, s
)
1950 # recurse, but not for nested modules
1951 if v
.refs
and deep
< self
._limit
_ \
1952 and not (deep
and ismodule(obj
)):
1953 # add sizes of referents
1954 r
, z
, d
= v
.refs
, self
._sizer
, deep
+ 1
1955 if sized
and deep
< self
._detail
_:
1956 # use named referents
1957 for o
in r(obj
, True):
1958 if isinstance(o
, _NamedRef
):
1959 t
= z(o
.ref
, d
, sized
)
1960 t
.name
= o
.name
# PYCHOK _sizer
1963 t
.name
= self
._nameof
(o
)
1965 s
+= t
.size
# PYCHOK _sizer
1966 else: # no sum(<generator_expression>) in Python 2.2
1967 s
+= sum(z(o
, d
, None) for o
in r(obj
, False))
1968 # recursion depth reached
1972 except RuntimeError: # XXX RecursionLimitExceeded:
1975 s
= sized(s
, f
, name
=self
._nameof
(obj
), refs
=rs
)
1978 def _sizes(self
, objs
, sized
=None):
1979 '''Return the size or an **Asized** instance for each given
1980 object and the total size. The total includes the size of
1981 any duplicates only once.
1983 self
.exclude_refs(*objs
) # skip refs to objs
1987 if i
in s
: # duplicate
1989 self
._duplicate
+= 1
1991 s
[i
] = self
._sizer
(o
, 0, sized
)
1994 s
= sum(i
.size
for i
in _values(s
))
1997 self
._total
+= s
# accumulate
2000 def asized(self
, *objs
, **opts
):
2001 '''Sizes each object and returns an **Asized** instance with
2002 size information and *referents* up to the given detail level
2003 (and with modified options, see method **set**).
2005 If only one object is given, the return value is the **Asized**
2006 instance for that object.
2010 _
, t
= self
._sizes
(objs
, Asized
)
2015 def asizeof(self
, *objs
, **opts
):
2016 '''Return the combined size of the given objects (with modified
2017 options, see method **set**).
2021 s
, _
= self
._sizes
(objs
, None)
2024 def asizesof(self
, *objs
, **opts
):
2025 '''Return the individual sizes of the given objects (with
2026 modified options, see method **set**).
2030 _
, t
= self
._sizes
(objs
, None)
2033 def _get_duplicate(self
):
2034 '''Number of duplicate objects seen so far.
2036 return self
._duplicate
2037 duplicate
= property(_get_duplicate
, doc
=_get_duplicate
.__doc
__)
2039 def exclude_refs(self
, *objs
):
2040 '''Excludes any references to the specified objects from sizing.
2042 While any references to the given objects are excluded, the
2043 objects will be sized if specified as positional arguments in
2044 subsequent calls to methods **asizeof** and **asizesof**.
2047 self
._seen
.setdefault(id(o
), 0)
2049 def exclude_types(self
, *objs
):
2050 '''Exclude the specified object instances and types from sizing.
2052 All instances and types of the given objects are excluded, even
2053 objects specified as positional arguments in subsequent calls
2054 to methods **asizeof** and **asizesof**.
2057 for t
in _keytuple(o
):
2058 if t
and t
not in self
._excl
_d
:
2061 def _get_missed(self
):
2062 '''Number of objects missed due to errors.
2065 missed
= property(_get_missed
, doc
=_get_missed
.__doc
__)
2067 def print_profiles(self
, w
=0, cutoff
=0, **print3opts
):
2068 '''Prints the profiles above *cutoff* percentage.
2070 The available options and defaults are:
2072 *w=0* -- indentation for each line
2074 *cutoff=0* -- minimum percentage printed
2076 *print3opts* -- print keyword arguments, like Python 3.+
2078 # get the profiles with non-zero size or count
2079 t
= [(v
, k
) for k
, v
in _items(self
._profs
) if v
.total
> 0 or v
.number
> 1]
2080 if (len(self
._profs
) - len(t
)) < 9: # just show all
2081 t
= [(v
, k
) for k
, v
in _items(self
._profs
)]
2085 s
= ' (% of grand total)'
2086 c
= max(cutoff
, self
._cutoff
)
2087 c
= int(c
* 0.01 * self
._total
)
2090 self
._printf
('%s%*d profile%s: total%s, average, and largest flat size%s: largest object',
2091 linesep
, w
, len(t
), _plural(len(t
)), s
, self
._incl
, **print3opts
)
2093 for v
, k
in sorted(t
, reverse
=True):
2094 s
= 'object%(plural)s: %(total)s, %(avg)s, %(high)s: %(obj)s%(lengstr)s' % v
.format(self
._clip
_, self
._total
)
2095 self
._printf
('%*d %s %s', w
, v
.number
, self
._prepr
(k
), s
, **print3opts
)
2097 if r
> 1 and v
.total
< c
:
2098 c
= max(cutoff
, self
._cutoff
)
2099 self
._printf
('%+*d profiles below cutoff (%.0f%%)', w
, r
, c
)
2101 z
= len(self
._profs
) - len(t
)
2103 self
._printf
('%+*d %r object%s', w
, z
, 'zero', _plural(z
), **print3opts
)
2105 def print_stats(self
, objs
=(), opts
={}, sized
=(), sizes
=(), stats
=3.0, **print3opts
):
2106 '''Prints the statistics.
2108 The available options and defaults are:
2110 *w=0* -- indentation for each line
2112 *objs=()* -- optional, list of objects
2114 *opts={}* -- optional, dict of options used
2116 *sized=()* -- optional, tuple of **Asized** instances returned
2118 *sizes=()* -- optional, tuple of sizes returned
2120 *stats=0.0* -- print stats, see function **asizeof**
2122 *print3opts* -- print keyword arguments, like Python 3.+
2124 s
= min(opts
.get('stats', stats
) or 0, self
._stats
_)
2125 if s
> 0: # print stats
2126 t
= self
._total
+ self
._missed
+ sum(_values(self
._seen
))
2132 # print header line(s)
2136 self
._printf
('%sasized(...%s%s) ...', linesep
, c
, o
, **print3opts
)
2137 for i
in range(n
): # no enumerate in Python 2.2.3
2138 self
._printf
('%*d: %s', w
- 1, i
, sized
[i
], **print3opts
)
2140 self
._printf
('%sasized(%s): %s', linesep
, o
, sized
, **print3opts
)
2141 elif sizes
and objs
:
2142 self
._printf
('%sasizesof(...%s%s) ...', linesep
, c
, o
, **print3opts
)
2143 for z
, o
in zip(sizes
, objs
):
2144 self
._printf
('%*d bytes%s%s: %s', w
, z
, _SI(z
), self
._incl
, self
._repr
(o
), **print3opts
)
2147 t
= self
._repr
(objs
)
2148 self
._printf
('%sasizeof(%s%s%s) ...', linesep
, t
, c
, o
, **print3opts
)
2150 self
.print_summary(w
=w
, objs
=objs
, **print3opts
)
2151 if s
> 1: # print profile
2152 self
.print_profiles(w
=w
, cutoff
=_c100(s
), **print3opts
)
2153 if s
> 2: # print typedefs
2154 self
.print_typedefs(w
=w
, **print3opts
)
2156 def print_summary(self
, w
=0, objs
=(), **print3opts
):
2157 '''Prints the summary statistics.
2159 The available options and defaults are:
2161 *w=0* -- indentation for each line
2163 *objs=()* -- optional, list of objects
2165 *print3opts* -- print keyword arguments, like Python 3.+
2167 self
._printf
('%*d bytes%s%s', w
, self
._total
, _SI(self
._total
), self
._incl
, **print3opts
)
2169 self
._printf
('%*d byte aligned', w
, self
._mask
+ 1, **print3opts
)
2170 self
._printf
('%*d byte sizeof(void*)', w
, _sizeof_Cvoidp
, **print3opts
)
2173 d
= self
._duplicate
or ''
2175 d
= ', %d duplicate' % self
._duplicate
2176 self
._printf
('%*d object%s given%s', w
, n
, _plural(n
), d
, **print3opts
)
2177 t
= sum(1 for t
in _values(self
._seen
) if t
!= 0)
2178 self
._printf
('%*d object%s sized', w
, t
, _plural(t
), **print3opts
)
2180 t
= sum(_values(self
._excl
_d
))
2181 self
._printf
('%*d object%s excluded', w
, t
, _plural(t
), **print3opts
)
2182 t
= sum(_values(self
._seen
))
2183 self
._printf
('%*d object%s seen', w
, t
, _plural(t
), **print3opts
)
2184 if self
._missed
> 0:
2185 self
._printf
('%*d object%s missed', w
, self
._missed
, _plural(self
._missed
), **print3opts
)
2187 self
._printf
('%*d deepest recursion', w
, self
._depth
, **print3opts
)
2189 def print_typedefs(self
, w
=0, **print3opts
):
2190 '''Prints the types and dict tables.
2192 The available options and defaults are:
2194 *w=0* -- indentation for each line
2196 *print3opts* -- print keyword arguments, like Python 3.+
2198 for k
in _all_kinds
:
2199 # XXX Python 3.0 doesn't sort type objects
2200 t
= [(self
._prepr
(a
), v
) for a
, v
in _items(_typedefs
) if v
.kind
== k
and (v
.both
or self
._code
_)]
2202 self
._printf
('%s%*d %s type%s: basicsize, itemsize, _len_(), _refs()',
2203 linesep
, w
, len(t
), k
, _plural(len(t
)), **print3opts
)
2204 for a
, v
in sorted(t
):
2205 self
._printf
('%*s %s: %s', w
, '', a
, v
, **print3opts
)
2206 # dict and dict-like classes
2207 t
= sum(len(v
) for v
in _values(_dict_classes
))
2209 self
._printf
('%s%*d dict/-like classes:', linesep
, w
, t
, **print3opts
)
2210 for m
, v
in _items(_dict_classes
):
2211 self
._printf
('%*s %s: %s', w
, '', m
, self
._prepr
(v
), **print3opts
)
2213 def _get_total(self
):
2214 '''Total size (in bytes) accumulated so far.
2217 total
= property(_get_total
, doc
=_get_total
.__doc
__)
2219 def reset(self
, align
=8, clip
=80, code
=False, derive
=False, # PYCHOK too many args
2220 detail
=0, ignored
=True, infer
=False, limit
=100, stats
=0,
2222 '''Resets the options, state, etc.
2224 The available options and defaults are:
2226 *align=8* -- size alignment
2228 *clip=80* -- clip repr() strings
2230 *code=False* -- incl. (byte)code size
2232 *derive=False* -- derive from super type
2234 *detail=0* -- **Asized** refs level
2236 *ignored=True* -- ignore certain types
2238 *infer=False* -- try to infer types
2240 *limit=100* -- recursion limit
2242 *stats=0.0* -- print statistics, see function **asizeof**
2244 *stream=None* -- output stream for printing
2246 See function **asizeof** for a description of the options.
2249 self
._align
_ = align
2252 self
._derive
_ = derive
2253 self
._detail
_ = detail
# for Asized only
2254 self
._infer
_ = infer
2255 self
._limit
_ = limit
2256 self
._stats
_ = stats
2257 self
._stream
= stream
2259 self
._ign
_d
= _kind_ignored
2264 self
.set(align
=align
, code
=code
, stats
=stats
)
2266 def set(self
, align
=None, code
=None, detail
=None, limit
=None, stats
=None):
2267 '''Sets some options. See also method **reset**.
2269 Any options not set remain unchanged from the previous setting.
2270 The available options are:
2272 *align* -- size alignment
2274 *code* -- incl. (byte)code size
2276 *detail* -- **Asized** refs level
2278 *limit* -- recursion limit
2280 *stats* -- print statistics, see function **asizeof**
2283 if align
is not None:
2284 self
._align
_ = align
2286 self
._mask
= align
- 1
2287 if (self
._mask
& align
) != 0:
2288 raise ValueError('invalid option: %s=%r' % ('align', align
))
2291 if code
is not None:
2293 if code
: # incl. (byte)code
2294 self
._incl
= ' (incl. code)'
2295 if detail
is not None:
2296 self
._detail
_ = detail
2297 if limit
is not None:
2298 self
._limit
_ = limit
2299 if stats
is not None:
2301 raise ValueError('invalid option: %s=%r' % ('stats', stats
))
2302 self
._stats
_ = s
= int(stats
)
2303 self
._cutoff
= _c100(stats
)
2304 if s
> 1: # profile types
2305 self
._profile
= True
2307 self
._profile
= False
2312 def adict(*classes
):
2313 '''Installs one or more classes to be handled as dict.
2317 # if class is dict-like, add class
2318 # name to _dict_classes[module]
2319 if isclass(c
) and _infer_dict(c
):
2320 t
= _dict_classes
.get(c
.__module
__, ())
2321 if c
.__name
__ not in t
: # extend tuple
2322 _dict_classes
[c
.__module
__] = t
+ (c
.__name
__,)
2323 else: # not a dict-like class
2325 return a
# all installed if True
2331 def asized(*objs
, **opts
):
2332 '''Return a tuple containing an **Asized** instance for each
2333 object passed as positional argument.
2335 The available options and defaults are:
2337 *align=8* -- size alignment
2339 *clip=80* -- clip repr() strings
2341 *code=False* -- incl. (byte)code size
2343 *derive=False* -- derive from super type
2345 *detail=0* -- **Asized** refs level
2347 *ignored=True* -- ignore certain types
2349 *infer=False* -- try to infer types
2351 *limit=100* -- recursion limit
2353 *stats=0.0* -- print statistics, see function **asizeof**
2355 If only one object is given, the return value is the **Asized**
2356 instance for that object. Otherwise, the length of the returned
2357 tuple matches the number of given objects.
2359 Set *detail* to the desired referents level and *limit* to the
2360 maximum recursion depth.
2362 See function **asizeof** for descriptions of the other options.
2365 raise KeyError('invalid option: %s=%r' % ('all', opts
['all']))
2367 _asizer
.reset(**opts
)
2368 t
= _asizer
.asized(*objs
)
2369 _asizer
.print_stats(objs
, opts
=opts
, sized
=t
) # show opts as _kwdstr
2376 def asizeof(*objs
, **opts
):
2377 '''Return the combined size (in bytes) of all objects passed
2378 as positional arguments.
2380 The available options and defaults are:
2382 *align=8* -- size alignment
2384 *all=False* -- all current objects
2386 *clip=80* -- clip ``repr()`` strings
2388 *code=False* -- incl. (byte)code size
2390 *derive=False* -- derive from super type
2392 *ignored=True* -- ignore certain types
2394 *infer=False* -- try to infer types
2396 *limit=100* -- recursion limit
2398 *stats=0.0* -- print statistics
2400 Set *align* to a power of 2 to align sizes. Any value less
2401 than 2 avoids size alignment.
2403 If *all* is True and if no positional arguments are supplied.
2404 size all current gc objects, including module, global and stack
2407 A positive *clip* value truncates all repr() strings to at
2408 most *clip* characters.
2410 The (byte)code size of callable objects like functions,
2411 methods, classes, etc. is included only if *code* is True.
2413 If *derive* is True, new types are handled like an existing
2414 (super) type provided there is one and only of those.
2416 By default certain base types like object, super, etc. are
2417 ignored. Set *ignored* to False to include those.
2419 If *infer* is True, new types are inferred from attributes
2420 (only implemented for dict types on callable attributes
2421 as get, has_key, items, keys and values).
2423 Set *limit* to a positive value to accumulate the sizes of
2424 the referents of each object, recursively up to the limit.
2425 Using *limit=0* returns the sum of the flat[4] sizes of
2426 the given objects. High *limit* values may cause runtime
2427 errors and miss objects for sizing.
2429 A positive value for *stats* prints up to 8 statistics, (1)
2430 a summary of the number of objects sized and seen, (2) a
2431 simple profile of the sized objects by type and (3+) up to
2432 6 tables showing the static, dynamic, derived, ignored,
2433 inferred and dict types used, found respectively installed.
2434 The fractional part of the *stats* value (x 100) is the
2435 cutoff percentage for simple profiles.
2437 See this module documentation for the definition of flat size.
2439 t
, p
= _objs_opts(objs
, **opts
)
2442 s
= _asizer
.asizeof(*t
)
2443 _asizer
.print_stats(objs
=t
, opts
=opts
) # show opts as _kwdstr
2450 def asizesof(*objs
, **opts
):
2451 '''Return a tuple containing the size (in bytes) of all objects
2452 passed as positional argments.
2454 The available options and defaults are:
2456 *align=8* -- size alignment
2458 *clip=80* -- clip ``repr()`` strings
2460 *code=False* -- incl. (byte)code size
2462 *derive=False* -- derive from super type
2464 *ignored=True* -- ignore certain types
2466 *infer=False* -- try to infer types
2468 *limit=100* -- recursion limit
2470 *stats=0.0* -- print statistics
2472 See function **asizeof** for a description of the options.
2474 The length of the returned tuple equals the number of given objects.
2477 raise KeyError('invalid option: %s=%r' % ('all', opts
['all']))
2478 if objs
: # size given objects
2479 _asizer
.reset(**opts
)
2480 t
= _asizer
.asizesof(*objs
)
2481 _asizer
.print_stats(objs
, opts
=opts
, sizes
=t
) # show opts as _kwdstr
2488 def _typedefof(obj
, save
=False, **opts
):
2489 '''Get the typedef for an object.
2492 v
= _typedefs
.get(k
, None)
2493 if not v
: # new typedef
2494 v
= _typedef(obj
, **opts
)
2500 def alen(obj
, **opts
):
2501 '''Return the length of an object (in *items*).
2503 See function **basicsize** for a description of the options.
2505 n
= t
= _typedefof(obj
, **opts
)
2508 if n
and _iscallable(n
):
2509 i
, v
, n
= t
.item
, t
.vari
, n(obj
)
2510 if v
and i
== _sizeof_Cbyte
:
2511 i
= getattr(obj
, v
, i
)
2512 if i
> _sizeof_Cbyte
:
2517 leng
= alen
# for backward comptibility
2520 def basicsize(obj
, **opts
):
2521 '''Return the basic size of an object (in bytes).
2523 The available options and defaults are:
2525 *derive=False* -- derive type from super type
2527 *infer=False* -- try to infer types
2529 *save=False* -- save the type definition if new
2531 b
= _typedefof(obj
, **opts
)
2537 def flatsize(obj
, align
=0, **opts
):
2538 '''Return the flat size of an object (in bytes), optionally aligned
2539 to a given power of 2.
2541 See function **basicsize** for a description of all other options.
2543 See this module documentation for the definition of *flat size*.
2545 v
= _typedefof(obj
, **opts
)
2549 if (align
& m
) != 0:
2550 raise ValueError('invalid option: %s=%r' % ('align', align
))
2553 v
= v
.flat(obj
, mask
=m
)
2557 def itemsize(obj
, **opts
):
2558 '''Return the item size of an object (in bytes).
2560 See function **basicsize** for a description of the options.
2562 i
= t
= _typedefof(obj
, **opts
)
2564 i
, v
= t
.item
, t
.vari
2565 if v
and i
== _sizeof_Cbyte
:
2566 i
= getattr(obj
, v
, i
)
2570 def named_refs(obj
, **opts
):
2571 """Returns (a generator for) all named *referents* of an object
2572 (re-using functionality from **asizeof**).
2574 See function **basicsize** for a description of the options.
2576 Does not return un-named *referents*, e.g. objects in a list.
2578 t
= _typedefof(obj
, **opts
)
2581 if r
and _iscallable(r
):
2582 for nr
in r(obj
, True):
2584 yield nr
.name
, nr
.ref
2585 except AttributeError:
2589 def refs(obj
, **opts
):
2590 '''Return (a generator for) specific *referents* of an object.
2592 See function **basicsize** for a description of the options.
2594 r
= t
= _typedefof(obj
, **opts
)
2597 if r
and _iscallable(r
):
2602 if __name__
== '__main__':
2604 if '-types' in sys
.argv
: # print static _typedefs
2606 w
= len(str(n
)) * ' '
2607 _printf('%s%d type definitions: %s and %s, kind ... %s', linesep
,
2608 n
, 'basic-', 'itemsize (alen)', '-type[def]s')
2609 for k
, v
in sorted((_prepr(k
), v
) for k
, v
in _items(_typedefs
)):
2610 s
= '%(base)s and %(item)s%(alen)s, %(kind)s%(code)s' % v
.format()
2611 _printf('%s %s: %s', w
, k
, s
)
2614 if '-gc' in sys
.argv
:
2616 import gc
# PYCHOK expected
2622 asizeof(all
=True, stats
=2) # print summary
2624 if '-v' in sys
.argv
:
2625 print('\n%s %s (Python %s)' % (__file__
, __version__
, sys
.version
.split()[0]))
2627 # License from the initial version of this source file follows:
2629 # --------------------------------------------------------------------
2630 # Copyright (c) 2002-2017 -- ProphICy Semiconductor, Inc.
2631 # All rights reserved.
2633 # Redistribution and use in source and binary forms, with or without
2634 # modification, are permitted provided that the following conditions
2637 # - Redistributions of source code must retain the above copyright
2638 # notice, this list of conditions and the following disclaimer.
2640 # - Redistributions in binary form must reproduce the above copyright
2641 # notice, this list of conditions and the following disclaimer in
2642 # the documentation and/or other materials provided with the
2645 # - Neither the name of ProphICy Semiconductor, Inc. nor the names
2646 # of its contributors may be used to endorse or promote products
2647 # derived from this software without specific prior written
2650 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2651 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2652 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2653 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2654 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2655 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2656 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2657 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2658 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
2659 # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2660 # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
2661 # OF THE POSSIBILITY OF SUCH DAMAGE.
2662 # --------------------------------------------------------------------