Search code examples
pythonpython-3.xsequenceargument-unpacking

Why does Python unpacking operator work with unordered collections


The Python 3 tutorial about the unpacking operator (*) generically speaks of a "list or tuple," while the error message for improper use says that a "sequence" is needed:

Python 3.5.1 (v3.5.1:37a07cee5969, Dec  6 2015, 01:38:48) [MSC v.1900 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> def f(a, b):
...     return a / b
...
>>> f(*1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() argument after * must be a sequence, not int

Python 3's Built-in types documentation lists the following sequence types:

  • Sequence Types — list, tuple, range
  • Text Sequence Type — str
  • Binary Sequence Types — bytes, bytearray, memoryview

Quick test:

>>> all(isinstance(x, collections.Sequence) for x in [[], (), range(1), '', b''])
True

Note that set types (like set and frozenset) and mapping types (dict) are not included here.

>>> any(isinstance(x, collections.Sequence) for x in [set(), {}])
False

My question: Why are all iterable types (including a set or dict) unpackable? They are not sequence types, as the TypeError above suggests they should be, and unordered behavior leads to undefined results when unpacking for positional args:

>>> def f(a, b):
...     return a / b
...
>>> f(*{4, 2})
0.5
>>> f(*{8, 2})
4.0
>>> f(*{4:1, 2:1})
0.5
>>> f(*{2:1, 8:1})
4.0

Solution

  • The error message is most likely a little bug*. Anything that is an iterable is accepted during function calls; this is hidden inside the section for Calls in the Python Reference Manual:

    If the syntax *expression appears in the function call, expression must evaluate to an iterable. Elements from these iterables are treated as if they were additional positional arguments.

    (Emphasis mine)

    *Which, as of 3.5.2 as @sytech pointed out, was fixed in Issue 4806 to correspond to the correct wording in the reference manual.