__sizeof__

__sizeof__(self)
Returns: int · Added in v3.0 · Updated April 1, 2026 · Dunder Methods
dunder-methods memory object-model

__sizeof__ returns the size of an object in bytes, as allocated by the Python interpreter. It measures only the object’s own memory footprint, not the total size of everything the object references.

Every Python object inherits __sizeof__ from object, so it’s available on all types — built-in and custom alike. Override it in your own classes to provide a meaningful size report.

Basic Usage

Call __sizeof__ on any object:

# Empty containers show base overhead
[].__sizeof__()              # 40
{}.__sizeof__()              # 216
"".__sizeof__()              # 49

# Sizes grow with content
[1, 2, 3].__sizeof__()       # 64
"hello".__sizeof__()         # 54
{"a": 1}.__sizeof__()        # 216

For lists and tuples, each element pointer costs 8 bytes on a 64-bit interpreter. Strings include their character data in the object itself.

__sizeof__ vs sys.getsizeof()

These two get confused, but they’re different:

__sizeof__()sys.getsizeof()
What it measuresObject’s raw sizeObject size + GC bookkeeping
TypeMethod on objectFunction in sys module
GC overheadNot includedIncluded for tracked objects
import sys

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person('Alice', 30)
print(p.__sizeof__())       # 32 — object's own size
print(sys.getsizeof(p))     # 56 — adds GC overhead

The 24-byte gap is the garbage collector’s header overhead. sys.getsizeof always calls __sizeof__ first, then adds extra bytes for objects the GC tracks.

Note that sys.getsizeof does not add GC overhead for all types. For simple types like int, it calls __sizeof__ directly with nothing added.

Custom Class Implementation

Override __sizeof__ to report your object’s actual memory footprint. Call object.__sizeof__(self) to get the base instance size:

class Point:
    __slots__ = ('x', 'y')

    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __sizeof__(self):
        return object.__sizeof__(self)

p = Point(1, 2)
print(p.__sizeof__())  # Smaller than a class with __dict__

Without __slots__, the instance will also have a __dict__. If you override __sizeof__ and don’t account for it, you’ll underreport the actual size:

import sys

class BadPoint:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __sizeof__(self):
        return object.__sizeof__(self)  # Missing __dict__!

class GoodPoint:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __sizeof__(self):
        return object.__sizeof__(self) + sys.getsizeof(self.__dict__)

bp = BadPoint(1, 2)
gp = GoodPoint(1, 2)
print(bp.__sizeof__())  # Undercounts
print(gp.__sizeof__())  # Accurate

Gotchas

Sizes differ between Python implementations. CPython, PyPy, and Jython have different memory layouts. Compare sizes only within the same interpreter.

__sizeof__ is shallow. It measures only the object itself. A list reports its own size, not the combined size of every element inside it. Use sys.getsizeof recursively if you need a deep picture.

Dict sizes don’t grow linearly. An empty dict and a dict with one key often report the same size because dicts grow in bucket-based chunks, not by one entry at a time.

# Dict grows in jumps, not linearly
{}.__sizeof__()            # 216
{"a": 1}.__sizeof__()      # 216 — same bucket size
{"a": 1, "b": 2}.__sizeof__()  # 216 — still same

See Also

  • sys.getsizeof() — measure object size including GC overhead
  • __slots__ — reduce instance size by eliminating __dict__