2013-03-06 9 views
17

Wszyscy wiemypyton listowego z wielu „, jeśli na

[f(x) for x in y if g(x)] 

składni Pythona.

Jednak AST reprezentacja listowego ma miejsca na więcej niż jeden „czy” wyrażenie:

comprehension = (expr target, expr iter, expr* ifs) 

Może ktoś dać mi przykład kodu Pythona, które wytwarzają AST z więcej niż jednego „, jeśli ' wyrażenie?

Odpowiedz

28

Wystarczy stosu je jeden po drugim:

[i for i in range(100) if i > 10 if i < 50] 

produkuje całkowitymi między 11 a 49, włącznie.

+5

Dlaczego jest to potrzebne, gdy będzie 'and' dokładnie osiągnąć ten sam wynik? –

+3

Więc jest to logiczne AND? –

+1

Nie mam pojęcia, dlaczego jest to potrzebne, ale tak, zachowuje się jak "i". Może to nie jest * potrzebne *, ale tylko cukier syntaktyczny. –

30

Gramatyka pozwala na wiele if ponieważ można wymieszać je między pętle:

[j for i in range(100) if i > 10 for j in range(i) if j < 20] 

Składniki zrozumieniem powinny być postrzegane jako zagnieżdżonych wypowiedzi, powyższe przekłada się:

lst = [] 
for i in range(100): 
    if i > 10: 
     for j in range(i): 
      if j < 20: 
       lst.append(j) 

Oznacza to również, że można używać wielu instrukcji if bez pętli for między:

[i for i in range(100) if i > 10 if i < 20] 

Chociaż nie sensical (wystarczy połączyć korzystających and lub z przykuty operatorów), to nie przekłada się na legalnej zagnieżdżonego zestawu sprawozdań jeszcze:

lst = [] 
for i in range(100): 
    if i > 10: 
     if i < 20: 
      lst.append(i) 

gramatyki i parsera nie specjalnie Disallow takiego wykorzystania , w taki sam sposób, w jaki Python nie zabrania ci gniazdowania instrukcji if.

+2

W rzeczywistości przytoczona część gramatyki AST nie jest konieczna do obsłużenia pierwszej części odpowiedzi. W tym przykładzie utworzymy dwa * generatory ze zrozumieniem * z pojedynczą instrukcją if. – poke

4

language reference daje lepsze wyobrażenie o tym:

list_comprehension ::= expression list_for 
list_for   ::= "for" target_list "in" old_expression_list [list_iter] 
list_iter   ::= list_for | list_if 
list_if    ::= "if" old_expression [list_iter] 

Jak widać lista rozumienie jest zdefiniowana za pomocą opcjonalnego list_iter na koniec-jednym list_iter. Teraz ten list_iter może być albo kolejnym częściowym zrozumieniem listy, albo warunkiem if. Sam stan if ponownie kończy się kolejnym opcjonalnym list_iter. Jest to niezbędne, aby umożliwić połączenie wielu części za pomocą opcjonalnych warunków if z tą samą listą. Fakt, że można również zbudować część .. if X if Y if Z dla list_iter jest tylko efektem ubocznym.

Tak więc, chociaż nie jest potrzebna możliwość łączenia wielu warunków if-alone, pozwala to na zdefiniowanie całej gramatyki.

-1

Wypróbuj poniższy kod:

>>> [i for i in range(50) if i in range(10,20)] 
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19] 

co daje rezultat integracyjnego.

2

Użycie wbudowanego all() umożliwia umieszczanie wielu wyrażeń lub funkcji logicznych w wyrażeniach iteracyjnych i pozostanie w zgodzie ze zrozumieniem.Wydaje mi się, że jest to dość nieużywane wbudowane i zapewnia wysoką czytelność.

>>> [x for x in range(20) if all([1 < x < 10, not x & 1])] 
[2, 4, 6, 8] 

Albo

>>> [x for x in range(20) if all([foo(x), bar(x)])] 

any() wbudowany będzie również pracować również tutaj, jeśli tylko jeden warunek musiał być spełniony:

>>> [x for x in range(20) if any([1 < x < 10, not x & 1])] 
[0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18] 
+0

Świetna odpowiedź. Czuje się wyraźniej i zwięźlej. –

+0

Należy pamiętać, że przy użyciu wszystkich() warunki będą zawsze oceniane (bez optymalizacji zwarć), a ponadto konieczne jest utworzenie listy dla każdego elementu pętli. – elias