2012-09-30 13 views
14

Piszę parser, aw procesie debugowania go, stwierdziliśmy, że widocznie jest to Python prawna:Co oznacza to stwierdzenie Pythona?

for [] in [[]]: print 0 

i tak jest to (!):

for [][:] in [[]]: print 0 

I nie winię parsera za to, że się myli ... Jestem Mam problem z ustaleniem, jak to zinterpretować!

Co dokładnie oznacza to stwierdzenie?

+0

google sekwencja rozpakowaniu. Powinien to wyjaśnić. – hendrik

Odpowiedz

14

Pod względem wykonania: nic.

Sama pętla for wykonuje pętlę nad pustą listą, więc nie będą wykonywane żadne iteracje.

I to dobrze, ponieważ for [] oznacza: przypisanie każdej pozycji w pętli do 0 zmiennych. Ta druga część prawdopodobnie jest tym, co cię zastanawia.

Instrukcja jest zgodna z prawem, ponieważ target token token_list umożliwia przypisanie wartości w sekwencji do równie dużej sekwencji nazw zmiennych; nazywamy to rozpakowywaniem krotek. Poniżej przedstawiono bardziej użyteczne przykłady list docelowych, w przydziale i usuwania:

(a, b, c) = range(3) 
del a, b, c 

Można zrobić to samo w for pętli:

nested = [[1,2,3], [4,5,6]] 
for a, b, c in nested: 
    print nested 

Można używać obu krotki i listy do target_list tokena jest to również legalne:

[a, b] = (1, 2) 

Jednak w Pythonie lista może być pusta. Tak więc, co następuje jest legalne, jednak nie sensical:

[] = [] 

i wreszcie, więc jest to:

nested_empty = [[], [], []] 
for [] in nested_empty: 
    pass 

Więcej zabawy z listami docelowych:

[][:] = [1, 2, 3] 

Teraz lewo strona podręczna używa plastra w zadaniu. Z dokumentacji:

Jeśli cel jest cięciem: Wyrażenie podstawowe w referencji jest oceniane. Powinno to dać zmienny obiekt (taki jak lista). Przypisany obiekt powinien być obiektem sekwencji tego samego typu. Następnie wyrażenia dolnej i górnej są oceniane, o ile są obecne; wartością domyślną są zero i długość sekwencji. Granice powinny oceniać (małe) liczby całkowite. Jeśli dowolne powiązanie jest ujemne, dodaje się do niego długość sekwencji. Powstałe granice są przycinane tak, aby leżały między zerem a długością sekwencji włącznie. Na koniec obiekt sekwencji jest proszony o zastąpienie wycinka elementami przypisanej sekwencji. Długość plastra może być różna od długości przypisanej sekwencji, zmieniając w ten sposób długość sekwencji docelowej, o ile obiekt na to pozwala.

Tak więc nie używamy już rozpakowywania krotek; zamiast tego zastępujemy sekcję listy po lewej stronie prawą listą. Ale ponieważ w naszym przykładzie lista po lewej stronie jest literalną listą anonimową, wynikowa zmieniona lista zostaje ponownie utracona.

Ponieważ jednak takie przyporządkowanie jest prawne w pętli, co następuje składni prawnych, aczkolwiek raczej niż sensical:

for [][:] in [range(i) for i in range(10)]: print 0 
+0

Ach, to wyjaśnia, dlaczego 'dla [] w [[]]: print 0' działa, ale co z' dla [] [:] w [[]]: print 0'? Jak to jest legalne/co to znaczy? – Mehrdad

+2

Lista nie jest pusta. Zawiera jeden element, który jest pustą listą. Tak więc 0 będzie drukowane. –

+0

@Mehrdad: Lewą stroną 'target_list' może być przypisanie plastra. 'alist [1: 2]' = somelist' zastępuje wycinek wskazany przez '[1: 2]' wartościami 'somelist'. Tak więc plaster jest prawidłowym wyrażeniem lewej strony dla przypisania i jest to również ważne w pętli. –

1
for [] in [[]]: print 0 

jest równoważna:

In [44]: for [x,y] in [[1,2],[3,4],[5,6]]: # or even (x,y) will work 
    print x,y 
    ....:  
    ....:  
1 2 
3 4 
5 6 

, ale poprzednia oczekuje, że nie zostanie zwrócona żadna wartość z listy, ja, e wartości na liście są puste lub ich len() s 0.

Nie można użyć tam (), ponieważ nie jest ona ważna.

bo w Pythonie można ALSS przypisać tak:

In [56]: x,y=[1,2]  #this means that the expression on RHS should return two values 
         # (x,y)=[1,2] or x,y=(1,2) or (x,y)=(1,2) all are valid 

In [57]: x 
Out[57]: 1 

In [58]: y 
Out[58]: 2 


In [62]: x,y='ab'  #assign a to x and b to y 

In [63]: x 
Out[63]: 'a' 

In [64]: y 
Out[64]: 'b' 
1

Oto mój najlepszy przypuszczenie:

for [] in [[]] oznacza „dla każdego wystąpienia [] (pusta lista obiektów) na tej liście [[]] (lista z dokładnie jednym elementem, który jest pustym obiektem listy), print 0.

W drugim przypadku, myślę, że [:] zadzwoni pod numer slice() w z wszystkimi wartościami domyślnymi, które po prostu zajmą kawałek całej listy. Wewnętrznie to może coś zrobić, na przykład zrobić kopię obiektu listy, ale efekt w tym przypadku powinien być taki sam.

+0

Uwaga: Ponieważ nie mam dostępu do Pythona na tym komputerze, opieram to na wynikach ze Skulptii, które w rezultacie wypisały '0'. Zakładam, że Skulpt (http://www.skulpt.org/) robi to samo, co CPython, co niekoniecznie jest bezpiecznym założeniem w tym przypadku narożnym. –

1

for..in struktura jest opisana w Pythonie ręcznego

http://docs.python.org/reference/compound_stmts.html#the-for-statement

Można mieć wiele zmiennych, na lewo od słowa kluczowego in

for [i,j] in [(1,2),(3,4),(5,6)]: 
    print i, j 

for [i,j] in [[1,2],[3,4],[5,6]]: 
    print i, j 

podręcznik powiedział, że jest zinterpretowane jako:

dla pierwszej iteracji i tak dalej. Dlatego możesz mieć pustą listę zmiennych, ponieważ lista iterowana ma pustą listę jako jedyny element. Ta pętla wydrukuje 0 raz.

Analizator składni, który czytasz, czy został wygenerowany automatycznie? Tego rodzaju oświadczenie może być generowane przez źródło inne niż ludzkie. Nie widzę tego celu.

+0

Ważną częścią jest atom "target" w instrukcji, który definiuje wyrażenie prawne z lewej strony. –

1
for [] in [[]]: print 0 

oznacza, że ​​dla każdego z pustymi iterables w [[]], która to lista, która zawiera pustą listę, druk 0. To nie jest ograniczone tylko do list, ale co iterables mogą być wprowadzane do tego. Możesz na przykład wypróbować:

# empty list, empty tuple, empty string, empty unicode 
for [] in [[],(), '', unicode()]: print 0 

i wyświetli 0 cztery razy.

[] [:] jest taki sam jak []. Zwróci pustą listę, więc moja odpowiedź jest taka sama jak powyżej.

0

Załóżmy, że masz listę krotek, który wygląda tak:

L = [(1,2), (3,4), (5,6)] 

Załóżmy, że chcesz wydrukować te krotki w jakiś szczególny sposób:

for tup in L: 
    a = tup[0] 
    b = tup[1] 
    if a<b: 
     print a,b 
    else: 
     print b,a 

Ale przypisywania a i b wyraźnie się zawartość tup jest raczej żmudna. Więc może to zrobić:

for tup in L: 
    a,b = tup 
    if a<b: 
     print a,b 
    else: 
     print b,a 

Ale można zrobić to nawet mniej uciążliwe:

for (a,b) in L: # you could also do "for [a,b] in L" 
    if a<b: 
     print a,b 
    else: 
     print b,a 

Tutaj (a,b) wzorzec pasuje do elementu, który jest zwracany przez iteracji. W pierwszym wykonaniu pętli for element zwracane przez iteracji jest (1,2), który dostaje wzór pasujący przeciwko (a,b), który w związku z tym przypisuje 1 do a i 2 do b

Teraz, w pierwszym przykładzie, jesteś iteracji nad lista zawierająca pustą listę. Oznacza to, że próbujesz wydrukować jak najwięcej 0 s, ponieważ na tej liście znajdują się []. Ale jest to nieco bardziej skomplikowane:

Kiedy próbujesz dopasować do wzorca, jak w moim trzecim przykładzie, python iteruje na liście (lub krotce) zmiennych i element zwracany przez iterator, jednocześnie przypisując wartości udać się. Jeśli więc twój wzorzec nie zawiera zmiennych, to element, który próbujesz dopasować do wzoru, powinien być również pusty (i iterowalny). To wyjaśnia następujące zachowanie:

>>> for i in 5: print i 
... 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not iterable 

>>> for [] in [[], 5]: print 0 
... 
0 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: 'int' object is not iterable 

... i to zachowanie TOO:

>>> x,y = (2,5,3) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack 

>>> for [] in [[], [5]]: print 0 
... 
0 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: too many values to unpack 

Teraz, gdy za drugim przykładzie, operacja [:] zasadzie tworzy kopię listy jest wywoływana, więc zmiana oryginalnej listy nie zmienia kopii i odwrotnie:

>>> L = [1,2,3] 
>>> M = L 
>>> M[0] = 'a' 
>>> print L[0] 
'a' 

>>> L = [1,2,3] 
>>> M = L[:] 
>>> M[0] = 'a' 
>>> print L[0] 
1 

Więc kiedy zadzwonisz [][:], wszystko robisz czyni nową listę pustą, który działa tak samo jak moje wyjaśnienia za pierwszym przykładzie