Or does it keep separated, in memory, a cache or a table where un-referenced values are stored?
Your guess above is more or less correct in CPython. There is a small integer intern, whith holds integers -5 to 256 inclusive on a default CPython build. See the macros defined here and here for those exact bounds.
The memory for these small integers is preallocated, so each assignment statement you've shown here retrieves a cached object from the intern. Neither 5 nor 7 will be created nor deleted because they were already interned, and they will remain in the intern until the interpreter exits.
So, assigning to these values will simply increment or decrement their reference counts, as you can check by using stdlib gc
module:
>>> import gc
>>> def counts():
... print("refcount5:", len(gc.get_referrers(5)))
... print("refcount7:", len(gc.get_referrers(7)))
...
>>> counts()
refcount5: 10
refcount7: 7
>>> myInt = 5 # this will increment 5's refcount
>>> counts()
refcount5: 11
refcount7: 7
>>> myInt = 7 # this will decrement 5's refcount and increment 7's
>>> counts()
refcount5: 10
refcount7: 8
>>> myInt2 = 5 # this will increment 5's refcount
>>> counts()
refcount5: 11
refcount7: 8
You can see the code which retrieves from intern here:
#define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS)
...
PyObject *
PyLong_FromLong(long ival)
{
...
if (IS_SMALL_INT(ival)) {
return get_small_int((sdigit)ival);
}
...
}
Note that interning integers is an implementation detail.