Tuples are immutable - you can't change their structure
>>> a = []
>>> tup = (a,)
>>> tup[0] is a # tup stores the reference to a
True
>>> tup[0] = a # ... but you can't re-assign it later
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> tup[0] = 'string' # ... same for all other objects
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
or size
>>> del tup[0] # Nuh uh
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item deletion
>>> id(tup)
139763805156632
>>> tup += ('something',) # works, because it creates a new tuple object:
>>> id(tup) # ... the id is different
139763805150344
after you create them.
On the other hand, mutable objects stored in a tuple do not lose their mutability e.g. you can still modify inner lists using list methods:
>>> a = []
>>> b, c = (a,), (a,) # references to a, not copies of a
>>> b[0].append(1)
>>> b
([1],)
>>> c
([1],)
Tuples can store any kind of object, although tuples that contain lists (or any other mutable objects) are not hashable:
>>> hash(b)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
The behaviour demonstrated above can indeed lead to confusing errors.