2016-07-07 6 views
18

Podczas korzystania try-z wyjątkiem pętli for kontekście poleceń wykonywanych do tej pory są oczywiście wykonane zWyjątek podczas sprawdzania listy. Czy wyniki pośrednie są przechowywane w dowolnym miejscu?

a = [1, 2, 3, 'text', 5] 

b = [] 
try: 
    for k in range(len(a)): 
     b.append(a[k] + 4) 
except: 
    print('Error!') 
print(b) 

wyników z

Error! 
[5, 6, 7] 

Jednak samo nie jest prawdą dla listowych

c=[] 
try: 
    c = [a[k] + 4 for k in range(len(a))] 
except: 
    print('Error!') 
print(c) 

Rezultatem jest

Error! 
[] 

Czy lista pośrednia, zbudowana przed wystąpieniem wyjątku, była przechowywana w dowolnym miejscu? Czy jest dostępny?

+0

Nie sądzę. – edwinksl

+2

Wartości prawdopodobnie nadal * znajdują się w pamięci * gdzieś, ale ponieważ przypisanie do 'c' nie powiodło się (ponieważ tworzenie wartości nie powiodło się), nie masz żadnego uchwytu w tej pamięci. Twoja klauzula "try" nie powiodła się, nie możesz oczekiwać, że coś w niej istnieje. W pierwszym przypadku przynajmniej 'b' został skonstruowany poza' try', więc jest gwarantowany. - Próbuję powiedzieć: ty * nie powinieneś tego * chcieć. – deceze

+4

BTW, dlaczego nie "[i + 4 for i in a]' ...?! – deceze

Odpowiedz

26

Wyniki pośrednie listy są przechowywane na wewnętrznym stosie CPython i nie są dostępne z wyrażeń Pythona, które są częścią listy zrozumiałej.

Zauważ, że Python wykonuje [.....]pierwszy, który tworzy obiekt listy, a tylko następnie cesjonariusze wynikające z nazwą c. Jeśli wystąpi wyjątek w wyrażeniu [....], wyrażenie zostaje zakończone, a zamiast tego uruchamiane są wyjątki. W związku z tym twoje wyrażenie print(c) może tylko pokazywać obiekt, który został, do którego został przypisany, a który tutaj jest obiektem z pustą listą. Mogło to być cokolwiek innego:

>>> c = 'Anything else' 
>>> try: 
...  c = [2 // i for i in (1, 0)] 
... except ZeroDivisionError: 
...  pass 
... 
>>> c 
'Anything else' 

W pierwszym przykładzie nie jest tworzony nowy obiekt listy. Zamiast tego manipulujesz (używając b.append()) istniejącym obiektem listy, dlatego możesz zobaczyć, co wszystkie udane połączenia b.append() zrobiły z nim. wygląd

11

Miejmy na kod bajtowy:

>>> def example(): 
...  c=[] 
...  try: 
...   c = [a[k] + 4 for k in range(len(a))] 
...  except: 
...   print('Error!') 
...  print(c) 
... 
>>> import dis 
>>> dis.dis(example) 

--- removed some instructions  

      27 GET_ITER    
     >> 28 FOR_ITER    20 (to 51) 
      31 STORE_FAST    1 (k) 
      34 LOAD_GLOBAL    2 (a) 
      37 LOAD_FAST    1 (k) 
      40 BINARY_SUBSCR  
      41 LOAD_CONST    1 (4) 
      44 BINARY_ADD   
      45 LIST_APPEND    2 
      48 JUMP_ABSOLUTE   28 
     >> 51 STORE_FAST    0 (c) 

--- more instructions... 

Jak widać, lista rozumienie jest tłumaczona na szereg instrukcji GET_ITER ... JUMP_ABSOLUTE. Następna instrukcja to STORE_FAST, która modyfikuje c. Jeśli wystąpi przed nim wyjątek, c nie zostanie zmodyfikowany.