5

I still learn python but this code seems beyond my level. what does it means?

 pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
Yan Gao
  • 181
  • 1
  • 3
  • 11
  • 2
    Have you seen list comprehensions before? And if so, have you tried reading [this question](http://stackoverflow.com/questions/1198777/double-iteration-in-list-comprehension)? – David Robinson Apr 01 '13 at 21:44
  • You're splitting the strings in `s1` with `;` as the delimiter, and on every item of that split list, you're splitting based on `&` as the delimiter, and you're putting the result of the second split into a list `pairs` – Tuxdude Apr 01 '13 at 21:45
  • you should look into "list comprehension" for information about the [a for a in whatever]. For more comment on your snippet you should provide detail on the qs object. Yet assuming it is a string, the for-in iterations operate on a list of strings which are spearated by (& and ;) – wirrbel Apr 01 '13 at 21:46
  • @Tuxdude: You've got it backward. You're splitting the strings in `qs` with `&` as the delimiter, and then splitting each of the results with `;` as the delimiter. – abarnert Apr 01 '13 at 21:49
  • @abarnert - oops! yes you're right, my bad!. – Tuxdude Apr 01 '13 at 22:00
  • @Tuxdude: And that's exactly why I don't use nested comprehension except in the most trivial of cases—everyone gets it wrong all the time (obviously including the most important reader of my code, me). – abarnert Apr 01 '13 at 22:04

1 Answers1

10

You can convert any list comprehension to an equivalent explicit loop like this:

pairs = []
for s1 in qs.split('&'):
    for s2 in s1.split(';'):
        pairs.append(s2)

The rule is to take all of the for and if clauses, nest them in the order they appear, and then append(foo) for whatever foo comes before the first clause.

The tutorial section on List Comprehension (and the subsection on Nested List Comprehensions) explains this… but it doesn't give you the simple rule for converting any comprehension into a nested block statement, which (in my opinion) makes it much easier to understand all but the trivial cases.

It's also worth noting that urllib.parse.parse_qsl (or urlparse.parse_qsl in 2.x) is a better way to parse query strings. Besides the fact that it doesn't involve a hard-to-read nested list comprehension, it also properly handles all kinds of things (like quoting) that you wouldn't think about in advance, and will end up debugging for one of your users who doesn't know how to submit useful bug reports.

abarnert
  • 354,177
  • 51
  • 601
  • 671
  • 3
    +1 for the point on nesting. For an embarrassingly long time, my brain always tried to read nested listcomps backwards, because I knew the append equivalent part was the "deepest" part, and that came first, so I thought you wrote it "upwards" from the deepest. Then one day on SO someone said "you write the loop part of list comprehensions in exactly the same order you'd write the loops, what's so hard?" and gave the example you just did. Ever since then, all was clear.. – DSM Apr 01 '13 at 21:59
  • Thanks very much for all help. Now I understand it. The most confuse part is first s2. The first for is out loop and second for is inner loop. So the first s2 means take output of s2 which is inner one. I get it. – Yan Gao Apr 01 '13 at 22:00
  • @DSM: Yeah, I had the same problem. If you only deal with non-nested comprehensions, you can read them from inside out. But once they're nested, you have to learn that the _actual_ rule is outside in, except that the first part which goes on the very inside. (And then, when dealing with genexps, you have to learn that the outermost iterator is actually lifted outside the whole expression, to make it even more fun…) – abarnert Apr 01 '13 at 22:03