开发者

Returing lists of tuple's keys and values

I can understand zip() function is used to construct a list of tuples like this:

x = ['a', 'b', 'c']
y = ['x', 'y', 'z', 'l']
lstTupA = zip(x,y)

lstTup开发者_开发知识库A would be [('a', 'x'), ('b', 'y'), ('c', 'z')].

lstA, lstB = zip(*lstTupA)

The above operation extracts the keys in the list of tuples to lstA and values in the list of tuples to lstB.

lstA was ('a', 'b', 'c') and lstB was ('x', 'y', 'z').

My query is this: Why are lstA and lstB tuples instead of lists? a, b and c are homogeneous and so are x, y and z. It's not logical to group them as tuples, is it?

Ideally lstA, lstB = zip(*lstTupA) should have assigned ['a', 'b', 'c'] to lstA and ['x', 'y', 'z'] to lstB (lists) right?

Some one please clarify!

Thanks.


"It's not logical to group them as tuples, is it?"

Yes. It is logical.

There are two kinds of built-in sequences. Lists and tuples.

The zip() function has n arguments, that defines the cardinality of the tuple to be fixed at n.

A list would only be appropriate if other arguments were somehow, magically, appended or not appended to the resulting sequence. This would mean sequences of variable length, not defined by the number of arguments to zip(). That would be a rather complex structure to build with a single function call.


zip is simply defined to behave this way:

In [2]: help(zip)
Help on built-in function zip in module __builtin__:

zip(...)
    zip(seq1 [, seq2 [...]]) -> [(seq1[0], seq2[0] ...), (...)]

    --> Return a list of tuples <--, where each tuple contains the i-th element
    from each of the argument sequences.  The returned list is truncated
    in length to the length of the shortest argument sequence.


What *lstTupA does in lstA, lstB = zip(*lstTupA) (or generally the * operator) i to flattening an iterable. So doing zip(*lstTupA) is equal to zip(lstTupA[0], lstTupA[1], ...) and these items are tuples passed to zip and that's exactly the reason why lstA and lstB are tuples.


zip doesn't know what is on the left hand side of the equal sign. As far as it know, lstTupA = zip(x,y) and lstA, lstB = zip(*lstTupA) are the same thing. zip is defined to do one thing and it is constant in doing that one thing. You have decided to break apart the list of tuples in the second statement, so you are the one that is adding extra context to the second statement.


Ideally lstA, lstB = zip(*lstTupA) should have assigned ['a', 'b', 'c'] to lstA and ['x', 'y', 'z'] to lstB (lists) right?

No, that is not right. Remember, that zip returns a list of tuples, that's exactly the way you expect it to behave when you say

lstTupA would be [('a', 'x'), ('b', 'y'), ('c', 'z')].

So, why would it return something different in the case of zip(*lstTupA)? It would still return the list of tuples, in this case [('a', 'b', 'c'), ('x', 'y', 'z')]. By performing assignment to lstA and lstB, you simply extract the tuples from the list.


Yes you have to do something stupid like

[list(t) for t in zip(*lst)]

Just to get lists.

What the 'pythonistas' rushing to defend the braindead choice of lists of tuples fail to remember is that tuples cannot be assigned to. Which makes zip(*m) useless for matrices or anything else where you want to alter items later.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜