Why subclasses of primitive types take more memory in Python?

I'm trying to subclass primitive types in Python like this (simplified version):

class MyInt(int):
    pass

I thought that an object of this class would take the same amount of memory as the primitive one. But, apparently, that's not true:

import sys
sys.getsizeof(10)          # 24
sys.getsizeof(MyInt(10))   # 72

Using __slots__, I was able to save some memory, but the subclass still takes more space:

class MyInt(int):
    __slots__ = ()


sys.getsizeof(10)          # 24
sys.getsizeof(MyInt(10))   # 56

If I subclass my own classes, on the other hand, the memory usage is the same:

class Father(object):
    pass


class Son(Father):
    pass

sys.getsizeof(Father())  # 64
sys.getsizeof(Son())     # 64
  1. Why does the subtype object use more memory than the primitive type object, if there are no extra fields?
  2. Is there a way to prevent (or minimize) this?

I'm using Python 2.7.12.

Upvotes: 1

Views: 306

Answers (1)

jsbueno
jsbueno

Reputation: 110271

Subclassing built-in classes was only possible in Python when "new style classes" were created in Python 2.2. So, without looking at the code, or reading carefully the presentation notes at this Guido's article, it is possible to infer that some boilerplate internal fields are needed in Python2 to allow built-in classes (which had their code base written prior to the unification) to work and behave well as "user defined classes" when subclassed. (That is "object" behavior that is not built-in the code base for "old-style" "int" objects).

Whatever takes place is somewhere inside Python's 2.7 Objects/typeobject.c - so you may take a look there (or wait until someone who can more easily analyse that come up with another answer)

That, as @blownhither_ma mentions in the comments above, seems not to be the case in Python3 anymore - I'd say the class unification have been consolidated since 2009:

In [158]: from sys import getsizeof as sizeof

In [159]: sizeof(int())
Out[159]: 24

In [160]: class MInt(int):
     ...:     __slots__ = ()
     ...:     

In [161]: sizeof(MInt())
Out[161]: 24

So, while there are things yet to be answered on your question, they matter only for Python 2, which no one should be using in new code by now.

Upvotes: 1

Related Questions