The fact that tuples are immutable makes me think that they can get special treatment from the python interpreter, until they are stored in a specific place that is not RAM ( equivalent, for example, to the use of the keyword register
in language c ).
In fact, in this tutorial on Youtube (around minute 9:40 ) it says precisely that, that the tuples are stored in a "special" place in memory.
Is this true? Does the interpreter store the tuples in a specific place that makes them more efficient?
No, it wouldn't make sense for the interpreter to use registers to store a tuple, unless that tuple was being part of a computation inside a loop where it was being accessed over and over again. But being an interpreted language, Python is quite "myopic" and only sees the statement it is executing. You don't see the full code to be able to perform those kinds of optimizations.
However, you can perform other types of optimizations. Because they are immutable, if in one part of the program you do something like:
and in another part of the program you do something like:
the interpreter could decide that the tuple object containing that pair of numbers
(1,2)
exists only once in memory , and thata
andb
refer to the same object. There is no problem with that decision, since the object is immutable so there is no risk that changing it througha
will have the secondary effect ofb
changing it.You can check if your interpreter has performed this type of optimization using the operator
is
that returnsTrue
when two variables point to the same object. I have verified that my Python does perform this optimization if you execute a .py (although it does not perform it if you do the experiment in the interactive interpreter):It also works with empty tuples:
Moreover, in the case of the empty tuple it turns out that this (empty) tuple is created beforehand as part of the interpreter. Every time the program requires an empty tuple, the previously created one is reused. We can check this using the function
id()
that returns a unique identifier of the object. Two objects with the sameid
, are the same object. In particular the CPython interpreter gives you the memory address where it is stored as a result ofid()
So we can create a variable
a
with an empty tuple, see itsid()
, destroy that variable (withdel a
), and theoretically the garbage collector should remove the empty tuple from memory. But since it's a pre-created tuple, it doesn't. If we create againa
we will see that it has the sameid
as the first time.This also works with a tuple like
(1,2)
(again, only when executing a .py and not in the interactive interpreter), which denotes that the garbage collector doesn't actually remove the tuples but keeps them in case they need to be used again shortly after. This does not do it for all the tuples, naturally, but it maintains a kind of cache and eliminates the ones it detects that are not used.The interpreter does other optimizations with the tuples. For example, although internally it saves them in a C array, when it comes to freeing that array (by the garbage collector), it is possible that instead of freeing it, it saves it in a linked list of "available space", in case it is going to need to immediately create another tuple of the same size, to be able to reuse that memory. This allows you to save memory, and above all it reduces the number of necessary operations
malloc()
.free()
This may result in slightly faster code than if we had used lists instead of tuples for these variablesa
andb
, but not because the tuples are stored in faster memory, but because the code that the interpreter uses to handle them requires fewer operations internally. .It makes sense to apply this type of optimization to tuples (and not to lists, for example) because precisely because tuples are immutable, they are more often created and destroyed without stopping. If we want to add an element to a tuple using for example
a=(1,2); a+=(3,4)
(valid operation), what happens is that a new tuple is created with(1,2,3,4)
and the old one is discarded with(1, 2)
, since the original cannot be changed (it is immutable). Since tuples are therefore subject to many creations and deletions, they are a priori more inefficient than lists, and so the interpreter strives to optimize memory management for them.In short, tuples are not more efficient than lists in terms of execution time, rather the opposite, and that forces the interpreter to do some juggling so that the penalty is not so great. Yes they can be more efficient in memory use, since it is not necessary to make copies of them. Many equal tuples are actually the same (more details in this answer from Alberto Rubiales , thanks @revliscano for pointing it out!)
The great advantage of tuples is not their supposed efficiency (which we have seen is practically marginal), but their immutability. Having a data type that cannot be changed is sometimes useful to make more robust programs, because although sometimes the programmer's intention is not to change a list, it happens that perhaps some function (sometimes not written by him) ends up changing it and it is difficult to detect where it happened. If you use a tuple instead, the modification attempt will throw an exception.
Tuples are more efficient because they have fewer features than lists. For example, they do not allow to be modified, and they do not allow the use of certain methods.