Round brackets are required in cases of ambiguity (if the tuple is part of a larger expression):
> Note that it is actually the comma which makes a tuple, not the parentheses. The parentheses are optional, except in the empty tuple case, or when they are needed to avoid syntactic ambiguity. For example, `f(a, b, c)` is a function call with three arguments, while `f((a, b, c))` is a function call with a 3-tuple as the sole argument.
```shell
>>> print(1,2,3,4,) # Calls print with 4 arguments: 1, 2, 3, and 4
The statement `t = 12345, 54321, 'hello!'` is an example of tuple packing: the values `12345`, `54321` and `'hello!'` are packed together in a tuple. The reverse operation is also possible:
```shell
>>> x, y, z = t
```
This is called, appropriately enough, sequence unpacking and works for any sequence on the right-hand side. Sequence unpacking requires that there are as many variables on the left side of the equals sign as there are elements in the sequence. Note that multiple assignment is really just a combination of tuple packing and sequence unpacking.
```shell
>>> t = 1, 2, 3 # Tuple packing.
>>> print(t)
(1, 2, 3)
>>> a, b, c = t # Sequence unpacking.
>>> print(a)
1
>>> print(b)
2
>>> print(c)
3
>>> d, e, f = 4, 5, 6 # Multiple assignment combines packing and unpacking.
>>> print(d)
4
>>> print(e)
5
>>> print(f)
6
>>> a, b = 1, 2, 3 # Multiple assignment requires each variable (right)
have a matching element (left).
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
`tuples` are immutable containers, guaranteeing **which** objects they contain will not change. It does **not** guarantee that the objects they contain will not change:
Functions can only return a single value, however, a heterogeneous `tuple` can be used to return multiple values from a function. One example is the built-in `enumerate` function that returns an iterable of heterogeneous `tuples`: