2016-08-29 9 views
17

Dlaczego list(next(iter(())) for _ in range(1)) zwraca pustą listę zamiast podnosić StopIteration?Dlaczego lista (następna (iter (())) dla _ w zakresie (1)) == []?

>>> next(iter(())) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
>>> [next(iter(())) for _ in range(1)] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
>>> list(next(iter(())) for _ in range(1)) # ?! 
[] 

To samo dzieje się z funkcji niestandardowej, która wyraźnie podnosi StopIteration:

>>> def x(): 
...  raise StopIteration 
... 
>>> x() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in x 
StopIteration 
>>> [x() for _ in range(1)] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in x 
StopIteration 
>>> list(x() for _ in range(1)) # ?! 
[] 
+1

Wow, bardzo podoba mi się odpowiedź w oryginalnym "duplikacie" pytania! – wheaties

+3

To jest błąd, jest adresowany za pomocą [PEP 479] (http://legacy.python.org/dev/peps/pep-0479/), gdzie 'StopIteration' zostanie przekonwertowany na' RuntimeError', aby lista nie przestaje niepoprawnie powtarzać, tak jak tego oczekujesz. –

+1

@ TadhgMcDonald-Jensen proszę podać to jako odpowiedź, aby móc głosować. – wheaties

Odpowiedz

9

zakładając wszystko pójdzie dobrze, zrozumienie generator x() for _ in range(1) powinna podnieść StopIteration po jej zakończeniu iteracji nad range(1) się wskazywać, że nie ma więcej elementów jucznych do listy.

Jednak ponieważ x() podnosi StopIteration kończy się opuszczeniem wcześnie znaczenie zachowanie to jest błąd w Pythonie, która jest skierowana z PEP 479

W Pythonie 3.6 lub za pomocą from __future__ import generator_stop w Pythonie 3.5, gdy StopIteration rozchodzi się dalej przekształcany jest do RuntimeError, więc list nie rejestruje tego jako końca zrozumienia. W takim przypadku błąd wygląda następująco:

Traceback (most recent call last): 
    File "/Users/Tadhg/Documents/codes/test.py", line 6, in <genexpr> 
    stuff = list(x() for _ in range(1)) 
    File "/Users/Tadhg/Documents/codes/test.py", line 4, in x 
    raise StopIteration 
StopIteration 

The above exception was the direct cause of the following exception: 

Traceback (most recent call last): 
    File "/Users/Tadhg/Documents/codes/test.py", line 6, in <module> 
    stuff = list(x() for _ in range(1)) 
RuntimeError: generator raised StopIteration 
6

Wyjątkiem StopIteration jest używane do przekazania podstawowych mechanizmów funkcji list gdy faktycznie zatrzymać iteracji na iterowalny że został do niego przekazany. W twoim przypadku mówisz Pythonowi, że rzeczą, która została przekazana do list() jest generator. Kiedy to osiągnie, wyświetla pustą listę, ponieważ nic nie zostało zgromadzone.

+0

Niepoprawnie, zatrzymanie iteracji z 'dla _ w zakresie (1)' powinno podnieść 'StopIteration' dla listy, aby zakończyć, ale tak nie jest, zamiast' x() 'podnosi błąd, który ** jest cicho stłumiony * * powodując przypadkowe zatrzymanie. To jest zmieniane w python3.6 i może być używane z 'od __future__ importuj generator_stop' w pythonie 3.5. zobacz [PEP 479] (http://legacy.python.org/dev/peps/pep-0479/) –

+2

@ TadhgMcDonald-Jensen Cieszę się, że został naprawiony, ale ponieważ jest to błąd, nie zmienia się fakt, że tak właśnie się dzieje. – wheaties

+0

@ TadhgMcDonald-Jensen Nie powiedziałbym, że odpowiedź wheaties jest błędna. Jednakże, jeśli mógłbyś to opublikować jako odpowiedź, chętnie bym to zaakceptował. –

Powiązane problemy