Skip to content

Commit c06a6d0

Browse files
Issue #25421: __sizeof__ methods of builtin types now use dynamic basic size.
This allows sys.getsize() to work correctly with their subclasses with __slots__ defined.
1 parent 6f3d5da commit c06a6d0

13 files changed

Lines changed: 46 additions & 13 deletions

File tree

‎Lib/test/test_sys.py‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# -*- coding: iso-8859-1 -*-
22
import unittest, test.test_support
33
from test.script_helper import assert_python_ok, assert_python_failure
4-
import sys, os, cStringIO
5-
import struct
4+
import cStringIO
5+
import gc
66
import operator
7+
import os
8+
import struct
9+
import sys
710

811
class SysModuleTest(unittest.TestCase):
912

@@ -754,6 +757,32 @@ class newstyleclass(object):
754757
check(xrange(1), size('3l'))
755758
check(xrange(66000), size('3l'))
756759

760+
def check_slots(self, obj, base, extra):
761+
expected = sys.getsizeof(base) + struct.calcsize(extra)
762+
if gc.is_tracked(obj) and not gc.is_tracked(base):
763+
expected += struct.calcsize('3P') # PyGC_Head
764+
self.assertEqual(sys.getsizeof(obj), expected)
765+
766+
def test_slots(self):
767+
# check all subclassable types defined in Objects/ that allow
768+
# non-empty __slots__
769+
check = self.check_slots
770+
class BA(bytearray):
771+
__slots__ = 'a', 'b', 'c'
772+
check(BA(), bytearray(), '3P')
773+
class D(dict):
774+
__slots__ = 'a', 'b', 'c'
775+
check(D(x=[]), {'x': []}, '3P')
776+
class L(list):
777+
__slots__ = 'a', 'b', 'c'
778+
check(L(), [], '3P')
779+
class S(set):
780+
__slots__ = 'a', 'b', 'c'
781+
check(S(), set(), '3P')
782+
class FS(frozenset):
783+
__slots__ = 'a', 'b', 'c'
784+
check(FS(), frozenset(), '3P')
785+
757786
def test_pythontypes(self):
758787
# check all types defined in Python/
759788
size = test.test_support.calcobjsize

‎Misc/NEWS‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Python 2.7.12?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #25421: __sizeof__ methods of builtin types now use dynamic basic size.
14+
This allows sys.getsize() to work correctly with their subclasses with
15+
__slots__ defined.
16+
1317
- Issue #19543: Added Py3k warning for decoding unicode.
1418

1519
- Issue #24097: Fixed crash in object.__reduce__() if slot name is freed inside

‎Modules/_collectionsmodule.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,7 +1103,7 @@ deque_sizeof(dequeobject *deque, void *unused)
11031103
Py_ssize_t res;
11041104
Py_ssize_t blocks;
11051105

1106-
res = sizeof(dequeobject);
1106+
res = _PyObject_SIZE(Py_TYPE(deque));
11071107
blocks = (deque->leftindex + deque->len + BLOCKLEN - 1) / BLOCKLEN;
11081108
assert(deque->leftindex + deque->len - 1 ==
11091109
(blocks - 1) * BLOCKLEN + deque->rightindex);

‎Modules/_io/bufferedio.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ buffered_sizeof(buffered *self, void *unused)
391391
{
392392
Py_ssize_t res;
393393

394-
res = sizeof(buffered);
394+
res = _PyObject_SIZE(Py_TYPE(self));
395395
if (self->buffer)
396396
res += self->buffer_size;
397397
return PyLong_FromSsize_t(res);

‎Modules/_io/bytesio.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -809,7 +809,7 @@ bytesio_sizeof(bytesio *self, void *unused)
809809
{
810810
Py_ssize_t res;
811811

812-
res = sizeof(bytesio);
812+
res = _PyObject_SIZE(Py_TYPE(self));
813813
if (self->buf)
814814
res += self->buf_size;
815815
return PyLong_FromSsize_t(res);

‎Modules/_struct.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1737,7 +1737,7 @@ s_sizeof(PyStructObject *self, void *unused)
17371737
{
17381738
Py_ssize_t size;
17391739

1740-
size = sizeof(PyStructObject) + sizeof(formatcode) * (self->s_len + 1);
1740+
size = _PyObject_SIZE(Py_TYPE(self)) + sizeof(formatcode) * (self->s_len + 1);
17411741
return PyLong_FromSsize_t(size);
17421742
}
17431743

‎Modules/arraymodule.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1541,7 +1541,7 @@ static PyObject *
15411541
array_sizeof(arrayobject *self, PyObject *unused)
15421542
{
15431543
Py_ssize_t res;
1544-
res = sizeof(arrayobject) + self->allocated * self->ob_descr->itemsize;
1544+
res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated * self->ob_descr->itemsize;
15451545
return PyLong_FromSsize_t(res);
15461546
}
15471547

‎Modules/mmapmodule.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ mmap__sizeof__method(mmap_object *self, void *unused)
655655
{
656656
Py_ssize_t res;
657657

658-
res = sizeof(mmap_object);
658+
res = _PyObject_SIZE(Py_TYPE(self));
659659
if (self->tagname)
660660
res += strlen(self->tagname) + 1;
661661
return PyLong_FromSsize_t(res);

‎Modules/parsermodule.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ parser_sizeof(PyST_Object *st, void *unused)
720720
{
721721
Py_ssize_t res;
722722

723-
res = sizeof(PyST_Object) + _PyNode_SizeOf(st->st_node);
723+
res = _PyObject_SIZE(Py_TYPE(st)) + _PyNode_SizeOf(st->st_node);
724724
return PyLong_FromSsize_t(res);
725725
}
726726

‎Objects/bytearrayobject.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2780,7 +2780,7 @@ bytearray_sizeof(PyByteArrayObject *self)
27802780
{
27812781
Py_ssize_t res;
27822782

2783-
res = sizeof(PyByteArrayObject) + self->ob_alloc * sizeof(char);
2783+
res = _PyObject_SIZE(Py_TYPE(self)) + self->ob_alloc * sizeof(char);
27842784
return PyInt_FromSsize_t(res);
27852785
}
27862786

0 commit comments

Comments
 (0)