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

96

Это правильный способ использования оператора 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".

гефан
источник
Для меня отсутствие необходимости помнить о close () в операторе finally - достаточно веская причина для использования 'with'. Я видел много кода, которому не удавалось закрыть свои ресурсы. Насколько я понимаю, «with» не имеет недостатков.
Рауль Салинас-Монтеагудо

Ответы:

140
  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операторов на внутренних уровнях.

Бернд Петерсон
источник
7

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

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

Питер Милли
источник
1

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

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

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

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

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

ЙоК
источник
-4

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

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()
Лео Лю
источник
1
Я добавил для вас форматирование кода; это облегчает чтение. Но вы можете дважды проверить, чтобы убедиться, что я не нарушил отступы.
andrewsi
2
Нет, ваша версия не выполняет то же самое, что исходный код. Даже если вы добавите отсутствующий readline()вызов, ваша версия не закроет файл, если в readline()результате будет получен файл IOError.
Алекси Торхамо,