Everything is a heap object
In CPython every value, an integer, a function, a class, even a module, is a PyObject living on the heap. At minimum each one carries two fields: a type pointer (ob_type) saying what it is, and a reference count (ob_refcnt) tracking how many references point at it.
x = 1000
type(x) # <class 'int'>
id(x) # heap address of the object
import sys
sys.getrefcount(x) # how many references point here
There are no primitives sitting on the stack the way there are in C or Java. 1000 is a full heap object with a header. This uniformity is the reason you can put anything in a list, pass anything to a function, and (if its type allows) give anything attributes.

