Znalazłem ten bit kodu w module, nad którym pracuję:

l = opaque_function()
thingys = [x for y in l for x in y]

Nie mogę tego przeczytać. Eksperymentem udało mi się określić, że spłaszczyło się do zagnieżdżonej liście 2-poziomowej, ale składnia jest nadal nieprzezroczysta. Oczywiście pominął niektóre opcjonalne wsporniki.

>>> l = [[1,2],[3,4]]
>>> [x for y in l for x in y]
[1, 2, 3, 4]

Moje oczy chcą przeanalizować ją jako: [x for y in [l for x in y] ] lub [ [x for y in l] for x in y ], ale oba osoby niepowodzeniem z powodu y nie są zdefiniowane.

Jak powinienem to czytać?

(Podejrzewam, że czuję się bardzo zawstydzony, gdy jest to wyjaśnione.)

6
Matthew Scouten 25 wrzesień 2012, 19:07

4 odpowiedzi

Najlepsza odpowiedź

Z Lista Wyświetla Dokumentacja:

Po dostarczeniu rozumienia listy składa się z pojedynczej ekspresji, a następnie co najmniej jeden {x0}} klauzula i zero lub więcej for lub if klauzule. W tym przypadku elementy nowej listy są te, które byłyby wytworzone przez rozważanie każdego z klauzul for lub if. Element za każdym razem, gdy osiągnięty jest wewnętrzny blok.

Tak więc wyrażenie można przepisać jako:

thingys = []
for y in l:
    for x in y:
        thingys.append(x)
5
Martijn Pieters 25 wrzesień 2012, 15:15

To naprawdę mnie mylisz. Powinieneś przeczytać go jak zagnieżdżona pętla:

new_list = []
for y in l:
    for x in y:
        new_list.append(x)

Staje się

for y in l for x in y [do] new_list.append(x)

Staje się

[x for y in l for x in y]
6
DSM 25 wrzesień 2012, 15:10

Powinieneś przeczytać to jako:

for y in l:
    for x in y:
        yield x

To wersja generatora, ale wszystkie kompensacje mają tę samą podstawową składnię: podczas gdy x jest umieszczony z przodu, reszta wyrażenia jest nadal odczytywana od lewej do prawej. Na początku byłem pomylony, spodziewałem się, że będzie na odwrót, ale ma sens po dodaniu wyrażeń filtrowania:

>>> l = [[1,2,3,4,5], [1,"foo","bar"], [2,3]]
>>> [x for y in l
...    if len(y) < 4
...    for x in y
...    if isinstance(x, int)]
[1, 2, 3]

Teraz wyobraź sobie, że musisz napisać całą rzeczą do tyłu:

[x if isinstance(x, int)
   for x in y
   if len(y) < 4
   for y in l]

To byłoby mylące nawet do weteranów prologów, nie wspominając o ludziach utrzymujących parserów Pythona :)

Bieżąca składnia pasuje również do tego, że w Haskell, który w pierwszej kolejności inspirowanej wszechświatowi.

5
Fred Foo 25 wrzesień 2012, 15:22
lis=[x for y in l for x in y] is Equivalent to:


lis=[]
for y in l:
   for x in y:
      lis.append(x)
1
Ashwini Chaudhary 25 wrzesień 2012, 15:10