Використання оператора python “with” із блоком try-Osim


96

Це правильний спосіб використовувати оператор python "with" у поєднанні з блоком try-Osim ?:

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: Перші кілька відповідей загалом говорять про переваги використання "з", але вони, здається, тут незначні. Ми всі роками (або повинні були) явно викликати f.close (). Я вважаю, одна перевага полягає в тому, що недбалі кодери виграють від використання "with".



Для мене відсутність необхідності пам’ятати закривати () речі в операторі нарешті є достатньою підставою для використання слова "with". Я бачив багато коду, який не міг закрити свої ресурси. І, наскільки я бачу, "with" не має недоліків.
Рауль Салінас-Монтеагудо,

Відповіді:


139
  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())

Окрім цього, я особисто вважаю поганою звичкою ловити будь-який виняток якомога раніше. Це не мета виключень. Якщо функція IO, яка може вийти з ладу, є частиною більш складної операції, у більшості випадків помилка 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.
Aleksi Torhamo
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.