Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unzipping and the * operator

Tags:

python

The python docs gives this code as the reverse operation of zip:

>>> x2, y2 = zip(*zipped) 

In particular

zip() in conjunction with the * operator can be used to unzip a list.

Can someone explain to me how the * operator works in this case? As far as I understand, * is a binary operator and can be used for multiplication or shallow copy...neither of which seems to be the case here.

like image 985
Leah Xue Avatar asked May 06 '11 22:05

Leah Xue


People also ask

What are Role of * operator within the zip () function?

Basically, it passes the contents of the lists as arguments.

What does * Zip do in Python?

Python's zip() function is defined as zip(*iterables) . The function takes in iterables as arguments and returns an iterator. This iterator generates a series of tuples containing elements from each iterable. zip() can accept any type of iterable, such as files, lists, tuples, dictionaries, sets, and so on.

How do I unzip a Zip file in Python?

To unzip a file in Python, use the ZipFile. extractall() method. The extractall() method takes a path, members, pwd as an argument and extracts all the contents.


1 Answers

Although hammar's answer explains how the reversing works in the case of the zip() function, it may be useful to look at argument unpacking in a more general sense. Let's say we have a simple function which takes some arguments:

>>> def do_something(arg1, arg2, arg3): ...     print 'arg1: %s' % arg1 ...     print 'arg2: %s' % arg2 ...     print 'arg3: %s' % arg3 ...  >>> do_something(1, 2, 3) arg1: 1 arg2: 2 arg3: 3 

Instead of directly specifying the arguments, we can create a list (or tuple for that matter) to hold them, and then tell Python to unpack that list and use its contents as the arguments to the function:

>>> arguments = [42, 'insert value here', 3.14] >>> do_something(*arguments) arg1: 42 arg2: insert value here arg3: 3.14 

This behaves as normal if you don't have enough arguments (or too many):

>>> arguments = [42, 'insert value here'] >>> do_something(*arguments) --------------------------------------------------------------------------- TypeError                                 Traceback (most recent call last)  /home/blair/<ipython console> in <module>()  TypeError: do_something() takes exactly 3 arguments (2 given) 

You can use the same construct when defining a function to accept any number of positional arguments. They are given to your function as a tuple:

>>> def show_args(*args): ...     for index, value in enumerate(args): ...         print 'Argument %d: %s' % (index, value) ... >>> show_args(1, 2, 3) Argument 0: 1 Argument 1: 2 Argument 2: 3 

And of course you can combine the two techniques:

>>> show_args(*arguments) Argument 0: 42 Argument 1: insert value here 

You can do a similar thing with keyword arguments, using a double asterix (**) and a dictionary:

>>> def show_kwargs(**kwargs): ...     for arg, value in kwargs.items(): ...         print '%s = %s' % (arg, value) ... >>> show_kwargs(age=24, name='Blair') age = 24 name = Blair 

And, of course, you can pass keyword arguments through a dictionary:

>>> values = {'name': 'John', 'age': 17} >>> show_kwargs(**values) age = 17 name = John 

It is perfectly acceptable to mix the two, and you can always have required arguments and optional extra arguments to a function:

>>> def mixed(required_arg, *args, **kwargs): ...     print 'Required: %s' % required_arg ...     if args: ...         print 'Extra positional arguments: %s' % str(args) ...     if kwargs: ...         print 'Extra keyword arguments: %s' % kwargs ... >>> mixed(1) Required: 1 >>> mixed(1, 2, 3) Required: 1 Extra positional arguments: (2, 3) >>> mixed(1, 2, 3, test=True) Required: 1 Extra positional arguments: (2, 3) Extra keyword arguments: {'test': True} >>> args = (2, 3, 4) >>> kwargs = {'test': True, 'func': min} >>> mixed(*args, **kwargs) Required: 2 Extra positional arguments: (3, 4) Extra keyword arguments: {'test': True, 'func': <built-in function min>} 

If you are taking optional keyword arguments and you want to have default values, remember you are dealing with a dictionary and hence you can use its get() method with a default value to use if the key does not exist:

>>> def take_keywords(**kwargs): ...     print 'Test mode: %s' % kwargs.get('test', False) ...     print 'Combining function: %s' % kwargs.get('func', all) ...  >>> take_keywords() Test mode: False Combining function: <built-in function all> >>> take_keywords(func=any) Test mode: False Combining function: <built-in function any> 
like image 132
Blair Avatar answered Oct 14 '22 04:10

Blair