I wrote the following code to check if integers are passed by value or reference.
foo = 1
def f(bar):
print id(foo) == id(bar)
bar += 1
print foo, b
In Python, like in many modern OO languages
foo = 1
actually creates an object with the value 1
and assigns a reference to the alias foo
. The internal type of foo is PyIntObject. This means Python isn't using the CPU / hardware int type, it always uses objects to handle numbers internally. The correct term is "plain integer", btw.
But creating objects is very expensive. That's why Python keeps an internal cache for a few numbers. Which means:
foo = 1
bar = 1
assert id(foo) == id(bar)
This isn't guaranteed, it's just a side effect of the implementation.
Number types in Python are also immutable. So even though bar
in your example is an alias for the cached int number, changing bar
doesn't modify the internal value. Instead, bar
is pointed to another instance which is why the id changes.
Because of the aforementioned optimization, this works as well:
foo = 1
bar = 1
assert id(foo) == id(bar)
bar += 1
assert id(foo) != id(bar)
bar -= 1
assert id(foo) == id(bar)