К моему стыду, я не могу понять, как обработать исключение для оператора python «with». Если у меня есть код:
with open("a.txt") as f:
print f.readlines()
Я действительно хочу обработать «файл не найден исключение», чтобы сделать что-то. Но я не могу написать
with open("a.txt") as f:
print f.readlines()
except:
print 'oops'
и не могу написать
with open("a.txt") as f:
print f.readlines()
else:
print 'oops'
Заключение 'with' в оператор try / исключением больше не работает: исключение не вызывается. Что я могу сделать, чтобы обработать сбой внутри оператора with с помощью Pythonic?
python
exception-handling
grigoryvp
источник
источник
with
Заявление не волшебно разорвать ограждающуюtry...except
заявление.Ответы:
Если вы хотите по-разному обрабатывать ошибки от вызова open и рабочего кода, который вы можете сделать:
источник
try...except
блоки внутрь,with
чтобы быть ближе к источнику исключения, которое не имеет ничего общего сopen()
.Лучший «Pythonic» способ сделать это, используя
with
оператор, приведен в Примере № 6 в PEP 343 , который дает основу для оператора.Используется следующим образом:
источник
try...except
оператор.Оператор with был доступен без
__future__
импорта с Python 2.6 . Вы можете получить его уже в Python 2.5 (но сейчас самое время обновить его) с помощью:Вот самая близкая вещь, которую нужно исправить. Вы почти у цели, но у
with
вас нетexcept
пункта:__exit__
Метод менеджера контекста , если он вернется,False
вызовет ошибку, когда она завершится. Если он вернетсяTrue
, он его подавит.open
Встроенное это__exit__
не возвращаетсяTrue
, так что вам просто нужно гнездо его в попытке, за исключением блока:И стандартный шаблон: не используйте голый,
except:
который ловитBaseException
и каждое возможное исключение и предупреждение. Будьте как минимум так же конкретны, какException
и для этой ошибки, возможно, поймайтеIOError
. Только ловить ошибки, которые вы готовы обрабатывать.Так что в этом случае вы бы сделали:
источник
Различение возможных источников исключений, возникающих из составного
with
оператораРазличать исключения, возникающие в
with
выражении, довольно сложно, поскольку они могут возникать в разных местах. Исключения могут быть вызваны из любого из следующих мест (или вызываемых там функций):ContextManager.__init__
ContextManager.__enter__
with
ContextManager.__exit__
Для получения более подробной информации см. Документацию о типах Context Manager .
Если мы хотим провести различие между этими различными случаями, просто завернуть
with
в atry .. except
недостаточно. Рассмотрим следующий пример (используяValueError
в качестве примера, но, конечно, его можно заменить любым другим типом исключения):Здесь
except
будут вылавливаться исключения, возникающие во всех четырех разных местах и, следовательно, не позволяющие различать их. Если мы переместим создание экземпляра объекта менеджера контекста за пределыwith
, мы можем различить__init__
иBLOCK / __enter__ / __exit__
:Фактически это только помогло с
__init__
частью, но мы можем добавить дополнительную переменную часового, чтобы проверить, является ли телоwith
запущенного для выполнения (то есть, различие между__enter__
и другими):Сложность состоит в том, чтобы различать исключения, происходящие из
BLOCK
и__exit__
потому, чтоwith
будет передано исключение, выходящее за пределы тела,__exit__
которое может решить, как его обработать (см. Документы ). Однако, если он__exit__
поднимется сам, исходное исключение будет заменено новым. Чтобы справиться с этими случаями, мы можем добавить общееexcept
предложение в телеwith
для хранения любого потенциального исключения, которое в противном случае могло бы остаться незамеченным, и сравнить его с тем, которое попало в крайний случайexcept
позже - если они совпадают, это означает, что источник былBLOCK
или иначе это было__exit__
(в случае__exit__
подавления исключения, возвращая истинное значение самое внешнееexcept
просто не будет казнен).Альтернативный подход с использованием эквивалентной формы, упомянутой в PEP 343
PEP 343. - Оператор «with» определяет эквивалентную «не-» версию
with
оператора. Здесь мы можем легко обернуть различные частиtry ... except
и, таким образом, провести различие между различными потенциальными источниками ошибок:Обычно более простой подход подойдет
Необходимость такой специальной обработки исключений должна быть довольно редкой, и обычно достаточно будет обернуть все
with
вtry ... except
блок. Особенно, если различные источники ошибок указаны разными (пользовательскими) типами исключений (менеджеры контекста должны быть разработаны соответствующим образом), мы можем легко различить их. Например:источник