SoFunction
Updated on 2024-11-07

Explaining Python function parameter splitting in detail

This article is a reading of notes and expanded understanding of 3.5 Function Argument Unpacking from the book Python Tricks: The Book. Function Argument Unpacking is the process of defining Variable Arguments (VarArgs).*args cap (a poem)**kwargs The inverse characteristic of the

*args cap (a poem)**kwars is that a function may define a formal parameter to receive an indeterminate number of incoming real parameters.

The function parameter disassembly here is to define more than one formal parameter and pass in only one object of the collection type (with a * or ** prefix) at the time of the call, such aslist, tuple, dict, evengenerator, then the function can automatically get the corresponding value from the collection object.

It would be nice to understand the following disassembly of parameters in assignments and Python 3.5's new* ** operations, then the properties described in this article are well understood.

The only set that is not passed as a parameter must be preceded by a * maybe**, in order to declare that the argument will be disassembled, rather than as a whole as a function argument. Add * maybe ** With Java's@SafeVarargs The closest thing to a similar effect is Scala'sfoo(Array[String]("d", "e") : _*) Writing method. See also:Java and Scala Ways of Calling Variable Parameters

Python's Assignment Disassembly Operations

>>> a, b = [1, 2] # a, b = (1, 2) also has the same effect
>>> print(a, b)
1 2
>>> a, b = {'x': 1, 'y':2}
>>> print(a, b)
x y
>>> a, b = {'x': 1, 'y':2}.keys()
>>> print(a, b)
x y
>>> a, b = {'x': 1, 'y':2}.values()
>>> print(a, b)
1 2
>>> a, b = (x * x for x in range(2))
>>> print(a, b)
0 1

New disassembly operations in Python 3.5

>>> [1, 2, *range(3), *[4, 5], *(6, 7)] # * number can break up the set, flatten(unwrap)
[1, 2, 0, 1, 2, 4, 5, 6, 7]
>>> {'x': 1, **{'y': 2, 'z': 3}}   # ** Unwrap the dictionary, flatten(unwrap) operation.
{'x': 1, 'y': 2, 'z': 3}

Somewhat like the functional programming flatten maybe unwrap Operation.

With the above foundation in place, we return to the example in the original book when we define the function that prints the 3-D coordinates as follows

def print_vector(x, y, z):
 print('<%s, %s, %s>' % (x, y, z))

It's not worth mentioning the way you pass three arguments in sequence, but now it's time to look at how you can use the function's parameter splitting feature to pass only a single collection parameter, so that theprint_vector function accurately obtains from the set the corresponding x, y, andz The value of the

Calling example for function parameter splitting

>>> list_vec = [2, 1, 3]
>>> print_vector(*list_vec)
<2, 1, 3>
>>> print_vector(*(2, 1, 3))
<2, 1, 3>
>>> dict_vec = {'y': 2, 'z': 1, 'x': 3}
>>> print_vector(*dict_vec) # equivalent to print_vector(*dict_vec.keys())
<y, z, x>
>>> print_vector(**dict_vec) # equivalent to print_vector(dict_vec['x'], dict_vec['y'], dict_vec['z'])
<3, 2, 1>
>>> genexpr = (x * x for x in range(3))
>>> print_vector(*genexpr)
<0, 1, 4>
>>> print_vector(*dict_vec.values()) # i.e. print_vector(*list(dict_vec.values()))
<2, 1, 3>

take note of **dict_vec It's a bit different in that its contents must be functionsprint_vector The formal parameters 'x', 'y', and 'z' are the three elements of the key.

Here are the various errors

**dict_vec Error when the number of elements is not correct, or the key does not match

>>> print_vector(**{'y': 2, 'z': 1, 'x': 3})
<3, 2, 1>
>>> print_vector(**{'y': 2, 'z': 1, 'a': 3})  # Key with 3 elements other than x, y, z
Traceback (most recent call last):
 File "<pyshell#39>", line 1, in <module>
 print_vector(**{'y': 2, 'z': 1, 'a': 3})
TypeError: print_vector() got an unexpected keyword argument 'a'
>>> print_vector(**{'y': 2, 'z': 1, 'x': 3, 'a': 4}) # contains x, y, z, but with four elements, key 'a' is not recognized
Traceback (most recent call last):
 File "<pyshell#40>", line 1, in <module>
 print_vector(**{'y': 2, 'z': 1, 'x': 3, 'a': 4})
TypeError: print_vector() got an unexpected keyword argument 'a'
>>> print_vector(**{'y': 2, 'z': 1})   # Missing element for key 'x'
Traceback (most recent call last):
 File "<pyshell#41>", line 1, in <module>
 print_vector(**{'y': 2, 'z': 1})
TypeError: print_vector() missing 1 required positional argument: 'x'

Mistakes without stars

>>> print_vector([2, 1, 3])
Traceback (most recent call last):
 File "<pyshell#44>", line 1, in <module>
 print_vector([2, 1, 3])
TypeError: print_vector() missing 2 required positional arguments: 'y' and 'z'

The collection object as a whole is taken as the first argument, so y and z are not passed in, so the function must be disassembled with the prefixes * or ** to notify the function of the arguments.

Error when the set length does not match the number of function arguments

>>> print_vector(*[2, 1])    # Split it into x=2, y=1, and what about z?
Traceback (most recent call last):
 File "<pyshell#47>", line 1, in <module>
 print_vector(*[2, 1])
TypeError: print_vector() missing 1 required positional argument: 'z'
>>> print_vector(*[2, 1, 3, 4])  # Even though it splits x=2, y=1, z=3, don't try to force a fourth element into the function (only three parameters are defined)
Traceback (most recent call last):
 File "<pyshell#48>", line 1, in <module>
 print_vector(*[2, 1, 3, 4])
TypeError: print_vector() takes 3 positional arguments but 4 were given

The two errors above correspond to the error when the disassembly at assignment is due to a mismatch in the number of elements

>>> a, b = [1]
Traceback (most recent call last):
 File "<pyshell#54>", line 1, in <module>
 a, b = [1]
ValueError: not enough values to unpack (expected 2, got 1)
>>> a, b = [1, 2, 3]
Traceback (most recent call last):
 File "<pyshell#55>", line 1, in <module>
 a, b = [1, 2, 3]
ValueError: too many values to unpack (expected 2)

Of course, when assigning values, Python can do something like this

a, b, *c = [1, 2, 3, 4]
>>> print(a, b, c)
1 2 [3, 4]

Added (2020-07-02): The Python term for iterative unpacking is Iterable Unpacking, found in the related PEP 448, PEP 3132, which is useful in practice, e.g., when unpacking strings to relate only to the fields you're interested in.

line = '2020-06-19 22:14:00  2688 '
date, time, size, name = () # Get all field values
_, time, _, name = ()   # Only interested in time and name
date, *_ = ()     # Only interested in the first date
*_, name = ()     # Only interested in the last name
date, *_, name = ()   # two-sided date, name interesting

This avoids using index numbers to refer to split values like split[0], splint[2], etc., and famous variables are less prone to error. Notice that Python is very smart when it comes to splitting, it knows how to correspond to positions, uses the asterisk (*) case, and understands how to handle how many to skip before, how many to skip in between, or how many elements to collect at the end.

Link:

PEP 448 -- Additional Unpacking Generalizations
PEP 3132 -- Extended Iterable Unpacking

Above is a detailed explanation of Python function parameter disassembly details, more information about python function parameter disassembly please pay attention to my other related articles!