The ID number of an object is an implementation detail of the
interpreter. There is almost no good reason to look at or care about the
ID number of objects.
You should remember that the id() function does not return the memory
location of the object except by accident. It is an accident of the
implementation that CPython happens to use memory locations for ID
numbers, but that is not a language guarantee and if CPython ever
changes to a compacting garbage collector, that absolutely will change.
Just like the Jython and IronPython interpreters, which already have
compacting garbage collectors, have ID numbers which are sequential
numbers 1, 2, 3, … And in PyPy, the interpreter does a lot of work to
preserve ID numbers that look like memory addresses even when the object
may have been unboxed into a machine value.
Another accident of implementation is that the interpreter might,
sometimes, cache small strings and reuse the same object multiple times.
In CPython, they may be reused if they look like identifiers. So when
you have two strings which look like identifiers, if the interpreter
caches them, you will get a single object and the ID number will be the
same:
s = "mynum"
t = "mynum"
id(s) == id(t) # returns True
But another interpreter, say, Jython or IronPython, may have different
rules for caching strings, or no cache at all. For example, in Jython
2.7.1 the same code returns False.
So if you are writing portable code that will run under any version of
Python, any interpreter, you cannot rely on accidents of implementation
like string caching.
There is almost no good reason to care about the id() of objects, and
there is no reason to treat it as a memory address.
Back to CPython. Here’s another example where the interpreter doesn’t
cache the strings even though the string looks like an identifier (in
this case, a really long identifier):
s = "abcdef"*10000
t = "abcdef"*10000
id(s) == id(t) # returns False in CPython 3.7
Now look at this:
s = "Hello World!!!"; t = "Hello World!!!"
If you run that line of code in the CPython interactive interpreter,
then id(s) == id(t)
will return True. But it must be in the
interactive interpreter, and the two assignments must be on the same
line separated by a semicolon. If you put them on different lines, it
won’t work. And it doesn’t work in a script.
Strings are immutable, so the Python interpreter, whether it is CPython,
MicroPython, IronPython, Jython, Stackless, PyPy, RustPython or some
other interpreter, is free to cache whatever strings it likes, whenever
it likes, for whatever reason it likes (saving memory, or speeding up
code, or both, or some other reason).
As a Python programmer, you cannot rely on strings being cached. The
rules for when they will be cached vary from version to version, and
from interpreter to interpreter, from platform to platform, and they can
change at any time with no warning.
Do not rely on strings having the same ID if they are equal.