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.
解释一:
zip(*zipped)
means "feed each element of zipped
as an argument to zip
". zip
is similar to transposing a matrix in that doing it again will leave you back where you started.
>>> a = [(1, 2, 3), (4, 5, 6)] >>> b = zip(*a) >>> b [(1, 4), (2, 5), (3, 6)] >>> zip(*b) [(1, 2, 3), (4, 5, 6)]
关于*和**的详细解释二:
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>