Использование python с оператором с блоком try-except

Это правильный способ использования оператора python "with" в сочетании с блоком try-except ?:

try:
    with open("file", "r") as f:
        line = f.readline()
except IOError:
    <whatever>

Если это так, то при старом способе работы:

try:
    f = open("file", "r")
    line = f.readline()
except IOError:
    <whatever>
finally:
    f.close()

Является ли здесь основное преимущество оператора with в том, что мы можем избавиться от трех строк кода? Мне это не кажется убедительным для этого варианта использования (хотя я понимаю, что оператор with имеет другие применения).

РЕДАКТИРОВАТЬ: идентичны ли функциональные возможности двух вышеуказанных блоков кода?

EDIT2: первые несколько ответов в целом говорят о преимуществах использования «with», но здесь они кажутся незначительными. Все мы (или должны были) явно вызывать f.close () в течение многих лет. Я полагаю, что одним из преимуществ является то, что неаккуратные кодеры выиграют от использования "with".


person gaefan    schedule 04.09.2010    source источник
comment
Возможный дубликат перехвата исключения при использовании оператора Python 'with'   -  person Filippo Mazza    schedule 04.10.2016
comment
Для меня отсутствие необходимости помнить о close () в операторе finally - достаточно веская причина для использования 'with'. Я видел много кода, которому не удавалось закрыть свои ресурсы. Насколько я понимаю, «with» не имеет недостатков.   -  person Raúl Salinas-Monteagudo    schedule 28.10.2019


Ответы (4)


  1. Указанные вами два блока кода не эквивалентны
  2. Код, который вы описали как старый способ работы, содержит серьезную ошибку: в случае сбоя открытия файла вы получите второе исключение в предложении finally, потому что f не привязан.

Эквивалентный код старого стиля будет:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

Как видите, оператор with может снизить вероятность ошибок. В более новых версиях Python (2.7, 3.1) вы также можете комбинировать несколько выражений в одном операторе with. Например:

with open("input", "r") as inp, open("output", "w") as out:
    out.write(inp.read())

Кроме того, я лично считаю плохой привычкой отлавливать любое исключение как можно раньше. Это не цель исключений. Если функция ввода-вывода, которая может дать сбой, является частью более сложной операции, в большинстве случаев ошибка IOError должна прервать всю операцию и, таким образом, обрабатываться на внешнем уровне. Используя операторы with, вы можете избавиться от всех этих try...finally операторов на внутренних уровнях.

person Bernd Petersohn    schedule 05.09.2010
comment
Раннее использование исключений - это нормально. Python во многих случаях поощряет их использование для управления. - person JeffCharter; 25.05.2021

Если содержимое блока finally определяется свойствами открываемого файлового объекта, почему бы разработчику файлового объекта не быть тем, кто записывает блок finally? Это преимущество оператора with, гораздо большее, чем сохранение трех строк кода в данном конкретном случае.

И да, способ, которым вы объединили with и try-except, в значительной степени является единственным способом сделать это, поскольку исключительные ошибки, вызванные внутри самого оператора open, не могут быть обнаружены в блоке with.

person Peter Milley    schedule 04.09.2010

Я думаю, вы ошиблись насчет утверждения "with", что оно сокращает только строки. На самом деле он выполняет инициализацию и разборку.

В вашем случае "с" делает

  • открыть файл,
  • обрабатывать его содержимое и
  • обязательно закройте его.

Вот ссылка для понимания оператора "с": http://effbot.org/zone/python-with-statement.htm

Изменить: Да, вы правильно используете «with», и функциональность обоих блоков кода идентична. Вопрос о том, зачем использовать «с»? это из-за преимуществ, которые вы получаете с ним. как вы упомянули о случайно пропущенном f.close ().

person YoK    schedule 04.09.2010

Более питонический способ для следующих кодов:

try:
    f = open("file", "r")
    try:
        line = f.readline()
    finally:
        f.close()
except IOError:
    <whatever>

try:
    f = open("file", "r")
except IOError:
    <whatever>
else:
    f.close()
person Leo Liu    schedule 13.10.2015
comment
Я добавил для вас форматирование кода; это облегчает чтение. Но вы можете дважды проверить, чтобы убедиться, что я не нарушил отступы. - person andrewsi; 14.10.2015
comment
Нет, ваша версия не выполняет то же самое, что и исходный код. Даже если вы добавите отсутствующий вызов readline(), ваша версия не закроет файл, если readline() приведет к IOError. - person Aleksi Torhamo; 14.10.2015