Closed
Description
Bug report
Most built-in types, when subclassed, will have a __sizeof__
that is 8 (pointer size) larger than the parent object, due to having an instance dictionary.
class UserFloat(float): pass
assert UserFloat().__sizeof__() - (0.0).__sizeof__() == 8
class UserTuple(tuple): pass
assert UserTuple().__sizeof__() - ().__sizeof__() == 8
class UserList(list): pass
assert UserList().__sizeof__() - [].__sizeof__() == 8
class UserDict(dict): pass
assert UserDict().__sizeof__() - {}.__sizeof__() == 8
This is unexpectedly, not the case for int
and set
, which exactly match the original __sizeof__
class UserSet(set): pass
print(UserSet().__sizeof__(), set().__sizeof__()) # 200 200
class UserInt(int): pass
print(UserInt().__sizeof__(), (0).__sizeof__()) # 24 24
As a result this makes __dictoffset__
usages incorrect as well
from ctypes import py_object
class UserTuple(tuple): pass
x = UserTuple()
x.a = 5
print(x.__dict__)
>> {'a': 5}
py_object.from_address(id(x) + x.__sizeof__() + UserTuple.__dictoffset__)
>> py_object({'a': 5})
from ctypes import py_object
class UserInt(int): pass
x = UserInt()
x.a = 5
print(x.__dict__)
>> {'a': 5}
py_object.from_address(id(x) + x.__sizeof__() + UserInt.__dictoffset__)
>> py_object(<NULL>)
Your environment
- CPython versions tested on: 3.11, 3.12.0a3