Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 00709aa

Browse files
committed
Merged revisions 63856-63857,63859-63860 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r63856 | robert.schuppenies | 2008-06-01 18:16:17 +0200 (So, 01 Jun 2008) | 2 lines Issue #2898: Added sys.getsizeof() to retrieve size of objects in bytes. ........ r63859 | georg.brandl | 2008-06-01 18:42:16 +0200 (So, 01 Jun 2008) | 2 lines Some style nits. Also clarify in the docstrings what __sizeof__ does. ........ r63860 | georg.brandl | 2008-06-01 19:05:56 +0200 (So, 01 Jun 2008) | 2 lines Fix test_descrtut. ........
1 parent 01a7d82 commit 00709aa

9 files changed

Lines changed: 254 additions & 2 deletions

File tree

Doc/library/sys.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,16 @@ always available.
331331
:func:`setrecursionlimit`.
332332

333333

334+
.. function:: getsizeof(object)
335+
336+
Return the size of an object in bytes. The object can be any type of
337+
object. All built-in objects will return correct results, but this
338+
does not have to hold true for third-party extensions as it is implementation
339+
specific.
340+
341+
.. versionadded:: 2.6
342+
343+
334344
.. function:: _getframe([depth])
335345

336346
Return a frame object from the call stack. If optional integer *depth* is

Lib/test/test_descrtut.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ def merge(self, other):
195195
'__rmul__',
196196
'__setattr__',
197197
'__setitem__',
198+
'__sizeof__',
198199
'__str__',
199200
'__subclasshook__',
200201
'append',

Lib/test/test_sys.py

Lines changed: 135 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: iso-8859-1 -*-
22
import unittest, test.support
3-
import sys, io
3+
import sys, io, os
44

55
class SysModuleTest(unittest.TestCase):
66

@@ -369,8 +369,141 @@ def test_ioencoding(self):
369369
self.assertEqual(out, b'?')
370370

371371

372+
class SizeofTest(unittest.TestCase):
373+
374+
def setUp(self):
375+
import struct
376+
self.i = len(struct.pack('i', 0))
377+
self.l = len(struct.pack('l', 0))
378+
self.p = len(struct.pack('P', 0))
379+
self.headersize = self.l + self.p
380+
if hasattr(sys, "gettotalrefcount"):
381+
self.headersize += 2 * self.p
382+
self.file = open(test.support.TESTFN, 'wb')
383+
384+
def tearDown(self):
385+
self.file.close()
386+
test.support.unlink(test.support.TESTFN)
387+
388+
def check_sizeof(self, o, size):
389+
result = sys.getsizeof(o)
390+
msg = 'wrong size for %s: got %d, expected %d' \
391+
% (type(o), result, size)
392+
self.assertEqual(result, size, msg)
393+
394+
def align(self, value):
395+
mod = value % self.p
396+
if mod != 0:
397+
return value - mod + self.p
398+
else:
399+
return value
400+
401+
def test_align(self):
402+
self.assertEqual(self.align(0) % self.p, 0)
403+
self.assertEqual(self.align(1) % self.p, 0)
404+
self.assertEqual(self.align(3) % self.p, 0)
405+
self.assertEqual(self.align(4) % self.p, 0)
406+
self.assertEqual(self.align(7) % self.p, 0)
407+
self.assertEqual(self.align(8) % self.p, 0)
408+
self.assertEqual(self.align(9) % self.p, 0)
409+
410+
def test_standardtypes(self):
411+
i = self.i
412+
l = self.l
413+
p = self.p
414+
h = self.headersize
415+
# bool
416+
self.check_sizeof(True, h + 2*l)
417+
# bytearray
418+
self.check_sizeof(bytes(), h + self.align(i) + l + p)
419+
# cell
420+
def get_cell():
421+
x = 42
422+
def inner():
423+
return x
424+
return inner
425+
self.check_sizeof(get_cell().__closure__[0], h + p)
426+
# code XXX wrong size
427+
# self.check_sizeof(get_cell().__code__, h + self.align(4*i) + 8*p +\
428+
# self.align(i) + 2*p)
429+
# complex
430+
self.check_sizeof(complex(0,1), h + 2*8)
431+
# enumerate
432+
self.check_sizeof(enumerate([]), h + l + 3*p)
433+
# reverse
434+
self.check_sizeof(reversed(''), h + l + p )
435+
# file XXX wrong size
436+
#self.check_sizeof(self.file, h + 4*p + self.align(2*i) + 4*p +\
437+
# self.align(3*i) + 3*p + self.align(i))
438+
# float
439+
self.check_sizeof(float(0), h + 8)
440+
# function
441+
def func(): pass
442+
self.check_sizeof(func, h + 11 * p)
443+
class c():
444+
@staticmethod
445+
def foo():
446+
pass
447+
@classmethod
448+
def bar(cls):
449+
pass
450+
# staticmethod
451+
self.check_sizeof(foo, h + l)
452+
# classmethod
453+
self.check_sizeof(bar, h + l)
454+
# generator
455+
def get_gen(): yield 1
456+
self.check_sizeof(get_gen(), h + p + self.align(i) + 2*p)
457+
# builtin_function_or_method
458+
self.check_sizeof(abs, h + 3*p)
459+
# module
460+
self.check_sizeof(unittest, h + p)
461+
# range
462+
self.check_sizeof(range(1), h + 3*p)
463+
# slice
464+
self.check_sizeof(slice(0), h + 3*p)
465+
466+
h += l
467+
# new-style class
468+
class class_newstyle(object):
469+
def method():
470+
pass
471+
# type (PyTypeObject + PyNumberMethods + PyMappingMethods +
472+
# PySequenceMethods + PyBufferProcs)
473+
# XXX wrong size
474+
# len_typeobject = p + 2*l + 15*p + l + 4*p + l + 9*p + l + 11*p
475+
# self.check_sizeof(class_newstyle,
476+
# h + len_typeobject + 42*p + 10*p + 3*p + 6*p)
477+
478+
479+
def test_specialtypes(self):
480+
i = self.i
481+
l = self.l
482+
p = self.p
483+
h = self.headersize
484+
# dict
485+
self.check_sizeof({}, h + 3*l + 3*p + 8*(l + 2*p))
486+
longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
487+
self.check_sizeof(longdict, h + 3*l + 3*p + 8*(l + 2*p) + 16*(l + 2*p))
488+
# list
489+
self.check_sizeof([], h + l + p + l)
490+
self.check_sizeof([1, 2, 3], h + l + p + l + 3*l)
491+
492+
h += l
493+
# long
494+
self.check_sizeof(0, h + self.align(2))
495+
self.check_sizeof(1, h + self.align(2))
496+
self.check_sizeof(-1, h + self.align(2))
497+
self.check_sizeof(32768, h + self.align(2) + 2)
498+
self.check_sizeof(32768*32768-1, h + self.align(2) + 2)
499+
self.check_sizeof(32768*32768, h + self.align(2) + 4)
500+
# XXX add Unicode support
501+
# self.check_sizeof('', h + l + self.align(i + 1))
502+
# self.check_sizeof('abc', h + l + self.align(i + 1) + 3)
503+
504+
372505
def test_main():
373-
test.support.run_unittest(SysModuleTest)
506+
test.support.run_unittest(SysModuleTest, SizeofTest)
374507

375508
if __name__ == "__main__":
376509
test_main()

Objects/bytesobject.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2784,6 +2784,17 @@ string_fromhex(PyObject *cls, PyObject *args)
27842784
return NULL;
27852785
}
27862786

2787+
PyDoc_STRVAR(sizeof__doc__,
2788+
"S.__sizeof__() -> size of S in memory, in bytes");
2789+
2790+
static PyObject *
2791+
string_sizeof(PyBytesObject *v)
2792+
{
2793+
Py_ssize_t res;
2794+
res = sizeof(PyBytesObject) + Py_SIZE(v) * Py_TYPE(v)->tp_itemsize;
2795+
return PyLong_FromSsize_t(res);
2796+
}
2797+
27872798

27882799
static PyObject *
27892800
string_getnewargs(PyBytesObject *v)
@@ -2848,6 +2859,8 @@ string_methods[] = {
28482859
translate__doc__},
28492860
{"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__},
28502861
{"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, zfill__doc__},
2862+
{"__sizeof__", (PyCFunction)string_sizeof, METH_NOARGS,
2863+
sizeof__doc__},
28512864
{NULL, NULL} /* sentinel */
28522865
};
28532866

Objects/dictobject.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1840,11 +1840,28 @@ dict_tp_clear(PyObject *op)
18401840

18411841
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
18421842

1843+
static PyObject *
1844+
dict_sizeof(PyDictObject *mp)
1845+
{
1846+
Py_ssize_t res;
1847+
1848+
res = sizeof(PyDictObject) + sizeof(mp->ma_table);
1849+
if (mp->ma_table != mp->ma_smalltable)
1850+
res = res + (mp->ma_mask + 1) * sizeof(PyDictEntry);
1851+
return PyLong_FromSsize_t(res);
1852+
}
1853+
1854+
PyDoc_STRVAR(has_key__doc__,
1855+
"D.has_key(k) -> True if D has a key k, else False");
1856+
18431857
PyDoc_STRVAR(contains__doc__,
18441858
"D.__contains__(k) -> True if D has a key k, else False");
18451859

18461860
PyDoc_STRVAR(getitem__doc__, "x.__getitem__(y) <==> x[y]");
18471861

1862+
PyDoc_STRVAR(sizeof__doc__,
1863+
"D.__sizeof__() -> size of D in memory, in bytes");
1864+
18481865
PyDoc_STRVAR(get__doc__,
18491866
"D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.");
18501867

@@ -1890,6 +1907,8 @@ static PyMethodDef mapp_methods[] = {
18901907
contains__doc__},
18911908
{"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST,
18921909
getitem__doc__},
1910+
{"__sizeof__", (PyCFunction)dict_sizeof, METH_NOARGS,
1911+
sizeof__doc__},
18931912
{"get", (PyCFunction)dict_get, METH_VARARGS,
18941913
get__doc__},
18951914
{"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS,

Objects/listobject.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,13 +2247,24 @@ list_init(PyListObject *self, PyObject *args, PyObject *kw)
22472247
return 0;
22482248
}
22492249

2250+
static PyObject *
2251+
list_sizeof(PyListObject *self)
2252+
{
2253+
Py_ssize_t res;
2254+
2255+
res = sizeof(PyListObject) + self->allocated * sizeof(void*);
2256+
return PyLong_FromSsize_t(res);
2257+
}
2258+
22502259
static PyObject *list_iter(PyObject *seq);
22512260
static PyObject *list_reversed(PyListObject* seq, PyObject* unused);
22522261

22532262
PyDoc_STRVAR(getitem_doc,
22542263
"x.__getitem__(y) <==> x[y]");
22552264
PyDoc_STRVAR(reversed_doc,
22562265
"L.__reversed__() -- return a reverse iterator over the list");
2266+
PyDoc_STRVAR(sizeof_doc,
2267+
"L.__sizeof__() -- size of L in memory, in bytes");
22572268
PyDoc_STRVAR(append_doc,
22582269
"L.append(object) -- append object to end");
22592270
PyDoc_STRVAR(extend_doc,
@@ -2279,6 +2290,7 @@ static PyObject *list_subscript(PyListObject*, PyObject*);
22792290
static PyMethodDef list_methods[] = {
22802291
{"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST, getitem_doc},
22812292
{"__reversed__",(PyCFunction)list_reversed, METH_NOARGS, reversed_doc},
2293+
{"__sizeof__", (PyCFunction)list_sizeof, METH_NOARGS, sizeof_doc},
22822294
{"append", (PyCFunction)listappend, METH_O, append_doc},
22832295
{"insert", (PyCFunction)listinsert, METH_VARARGS, insert_doc},
22842296
{"extend", (PyCFunction)listextend, METH_O, extend_doc},

Objects/longobject.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3625,6 +3625,17 @@ long_round(PyObject *self, PyObject *args)
36253625
#undef UNDEF_NDIGITS
36263626
}
36273627

3628+
static PyObject *
3629+
long_sizeof(PyLongObject *v)
3630+
{
3631+
Py_ssize_t res;
3632+
3633+
res = sizeof(PyLongObject) + abs(Py_SIZE(v)) * sizeof(digit);
3634+
if (Py_SIZE(v) != 0)
3635+
res -= sizeof(digit);
3636+
return PyLong_FromSsize_t(res);
3637+
}
3638+
36283639
#if 0
36293640
static PyObject *
36303641
long_is_finite(PyObject *v)
@@ -3651,6 +3662,8 @@ static PyMethodDef long_methods[] = {
36513662
"Rounding with an ndigits arguments defers to float.__round__."},
36523663
{"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS},
36533664
{"__format__", (PyCFunction)long__format__, METH_VARARGS},
3665+
{"__sizeof__", (PyCFunction)long_sizeof, METH_NOARGS,
3666+
"Returns size in memory, in bytes"},
36543667
{NULL, NULL} /* sentinel */
36553668
};
36563669

Objects/typeobject.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3275,6 +3275,20 @@ object_format(PyObject *self, PyObject *args)
32753275
return result;
32763276
}
32773277

3278+
static PyObject *
3279+
object_sizeof(PyObject *self, PyObject *args)
3280+
{
3281+
Py_ssize_t res, isize;
3282+
3283+
res = 0;
3284+
isize = self->ob_type->tp_itemsize;
3285+
if (isize > 0)
3286+
res = Py_SIZE(self->ob_type) * isize;
3287+
res += self->ob_type->tp_basicsize;
3288+
3289+
return PyLong_FromSsize_t(res);
3290+
}
3291+
32783292
static PyMethodDef object_methods[] = {
32793293
{"__reduce_ex__", object_reduce_ex, METH_VARARGS,
32803294
PyDoc_STR("helper for pickle")},
@@ -3284,6 +3298,8 @@ static PyMethodDef object_methods[] = {
32843298
object_subclasshook_doc},
32853299
{"__format__", object_format, METH_VARARGS,
32863300
PyDoc_STR("default object formatter")},
3301+
{"__sizeof__", object_sizeof, METH_NOARGS,
3302+
PyDoc_STR("__sizeof__() -> size of object in memory, in bytes")},
32873303
{0}
32883304
};
32893305

Python/sysmodule.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,39 @@ sys_mdebug(PyObject *self, PyObject *args)
609609
}
610610
#endif /* USE_MALLOPT */
611611

612+
static PyObject *
613+
sys_getsizeof(PyObject *self, PyObject *args)
614+
{
615+
static PyObject * str__sizeof__ = NULL;
616+
617+
/* Initialize static variable needed by _PyType_Lookup */
618+
if (str__sizeof__ == NULL) {
619+
str__sizeof__ = PyUnicode_InternFromString("__sizeof__");
620+
if (str__sizeof__ == NULL)
621+
return NULL;
622+
}
623+
624+
/* Type objects */
625+
if (PyType_Check(args)){
626+
PyObject *method = _PyType_Lookup(Py_TYPE(args),
627+
str__sizeof__);
628+
if (method == NULL) {
629+
PyErr_Format(PyExc_TypeError,
630+
"Type %.100s doesn't define __sizeof__",
631+
Py_TYPE(args)->tp_name);
632+
return NULL;
633+
}
634+
return PyObject_CallFunctionObjArgs(method, args, NULL);
635+
}
636+
else
637+
return PyObject_CallMethod(args, "__sizeof__", NULL);
638+
}
639+
640+
PyDoc_STRVAR(getsizeof_doc,
641+
"getsizeof(object) -> int\n\
642+
\n\
643+
Return the size of object in bytes.");
644+
612645
static PyObject *
613646
sys_getrefcount(PyObject *self, PyObject *arg)
614647
{
@@ -812,6 +845,7 @@ static PyMethodDef sys_methods[] = {
812845
{"getrefcount", (PyCFunction)sys_getrefcount, METH_O, getrefcount_doc},
813846
{"getrecursionlimit", (PyCFunction)sys_getrecursionlimit, METH_NOARGS,
814847
getrecursionlimit_doc},
848+
{"getsizeof", sys_getsizeof, METH_O, getsizeof_doc},
815849
{"_getframe", sys_getframe, METH_VARARGS, getframe_doc},
816850
#ifdef MS_WINDOWS
817851
{"getwindowsversion", (PyCFunction)sys_getwindowsversion, METH_NOARGS,
@@ -983,6 +1017,7 @@ getdlopenflags() -- returns flags to be used for dlopen() calls\n\
9831017
getprofile() -- get the global profiling function\n\
9841018
getrefcount() -- return the reference count for an object (plus one :-)\n\
9851019
getrecursionlimit() -- return the max recursion depth for the interpreter\n\
1020+
getsizeof() -- return the size of an object in bytes\n\
9861021
gettrace() -- get the global debug tracing function\n\
9871022
setcheckinterval() -- control how often the interpreter checks for events\n\
9881023
setdlopenflags() -- set the flags to be used for dlopen() calls\n\

0 commit comments

Comments
 (0)