Исключение во время понимания списка. Сохраняются ли промежуточные результаты в любом месте?

При использовании try-except в контексте цикла for команды, выполненные до сих пор, очевидно, выполняются с помощью

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

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

результат с

Error!
[5, 6, 7]

Тем не менее, это не относится к пониманию списков

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

И результат

Error!
[]

Является ли промежуточным списком, созданным до возникновения исключения, хранится где угодно? Доступен ли он?

Ответы

Ответ 1

Промежуточные результаты по составлению списка хранятся во внутреннем стеке CPython и не доступны из выражений Python, которые являются частью понимания списка.

Обратите внимание, что Python выполняет [.....] первый, который создает объект списка, и только , а затем присваивает этот результат имени c. Если в выражении [....] возникает исключение, выражение прекращается, и вместо этого обрабатывается обработка исключений. Таким образом, выражение print(c) может показывать только предыдущий объект, к которому привязан c, который представляет собой пустой объект списка. Это могло быть что-то еще:

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

В первом примере не создается новый объект списка. Вместо этого вы управляете (используя b.append()) существующий объект списка, поэтому вы можете видеть, что сделали с ним все успешные вызовы b.append().

Ответ 2

Посмотрим на байт-код:

>>> 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...

Как вы можете видеть, понимание списка переводится в ряд инструкций GET_ITER... JUMP_ABSOLUTE. Следующая команда STORE_FAST - это та, которая изменяет c. Если перед ним возникает какое-либо исключение, c не будет изменено.