[ Python: how multiple arguments work? ]
I'm new to Python and programming. Can someone explain the following codes in details?
def myzip(*seqs):
seqs = [list(S) for S in seqs]
res = []
while all(seqs):
res.append(tuple(S.pop(0) for S in seqs))
return res
>>> myzip([1, 2, 3], ['a', 'b', 'c'])
[(1, 'a'), (2, 'b'), (3, 'c')]
Especially, I don't understand the S
is for element in a list (e.g. 1
, 2
...) or the list ([1, 2, 3]
).
I think I need a detail explanation for each line.
Answer 1
In the list comprehension, S
is assigned each of the arguments passed to the function; seqs
is a list of arguments passed in, and you passed in two lists. So S
is first bound to [1, 2, 3]
then ['a', 'b', 'c']
.
>>> seqs = [[1, 2, 3], ['a', 'b', 'c']]
>>> seqs[0]
[1, 2, 3]
The first line just makes sure that all arguments are turned into lists, explicitly, so that you can later on call list.pop(0)
on each. This allows you to pass in strings, tuples, dictionaries, or any other iterable as an argument to this function:
>>> myzip('123', 'abc')
[('1', 'a'), ('2', 'b'), ('3', 'c')]
The while all(seqs):
loop then iterates until there is at least one argument that is empty. In other words, the loop terminates when the shortest sequence has been exhausted:
>>> myzip('1', 'abc')
[('1', 'a')]
In the loop, the first element of each of the input arguments is removed from the list and added to res
as a tuple. For the 2 input lists, that means that first (1, 'a')
is added to res
, followed by (2, 'b')
then (3, 'c')
.
Answer 2
seqs is the list of two separate lists: [1,2,3] and ['a', 'b', 'c']
Now while all(seqs):
will iterate through the elements of seqs - the two lists mentioned above.
We then create an empty list res and append to it tuple
objects.
Each tuple object will progressively contain the first element of each of the list in seqs. pop(0)
will return the first element and remove it from the list thus changing the list in place (lists are mutable).
Thus what you are doing is you are creating a list of tuples obtained by pairing the corresponding elements in both the lists.
When you say seqs = [list(S) for S in seqs]
, S refers to each of the list element in seqs. However, in this particular call to the function, since you are passing lists as elements this statement becomes redundant.
Answer 3
First You need to know what is zip
function. Because this function is doing the same job as zip in python.
def myzip(*seqs):
First line says this function gets as many argument you want and all of them will be gather in one list as seqs
. Usage like myzip([1, 2, 3], ['a', 'b', 'c'])
gives you seqs = [[1, 2, 3], ['a', 'b', 'c']]
.
seqs = [list(S) for S in seqs]
Then you want to make sure every item in seqs
are list items. This line convert every item to list. This is what list
does. (Even '123'
to ['1', '2', '3']
)
res = []
while all(seqs):
res.append(tuple(S.pop(0) for S in seqs))
return res
In these four lines it pops first element of each S
of seqs
and creates a tuple for final result. The final result is a list (res = []
).
In the loop condition: all(seqs)
it checks if all elements of seqs
are available. If one them goes empty it breaks the loop.
In side the loop, pop(0)
removes the first element from S
and return it as value S.pop(0)
. This way it updates all elements of seqs
. for next loop.
tuple
creates tuple like (1, 'a')
out of all first elements. Next iteration is going to be `(2, 'b') because all first elements popped before.
All these tuples in a list res
is its goal. res.append
adds these tuple to the final result.