Існує одна причина, чому віддається перевага наступному:
with open('filename.txt') as fp:
for line in fp:
print line
Всі ми зіпсовані відносно детермінованою схемою опорного рахунку CPython для вивезення сміття. Інші, гіпотетичні реалізації Python не обов'язково закриють файл "досить швидко" без withблоку, якщо вони використовують іншу схему для повернення пам'яті.
У такій реалізації ви можете отримати помилку "занадто багато файлів відкрито" в ОС, якщо ваш код відкриває файли швидше, ніж збирач сміття викликає фіналізатори на осиротілих файлових ручках. Звичайне рішення полягає в тому, щоб негайно запустити GC, але це неприємний злом, і це повинно виконувати кожна функція, яка могла б зіткнутися з помилкою, в тому числі в бібліотеках. Який кошмар.
Або ви могли просто використовувати withблок.
Бонусне питання
(Перестаньте читати зараз, якщо вас цікавлять лише об'єктивні аспекти питання.)
Чому це не включено в протокол ітератора для файлових об’єктів?
Це суб'єктивне питання щодо дизайну API, тому у мене є суб'єктивна відповідь у двох частинах.
На рівні кишок це відчувається неправильно, оскільки він змушує протокол ітератора робити дві окремі речі - перебирати рядки та закривати обробку файлів - і часто погана ідея змусити просту функцію виглядати робити дві дії. У цьому випадку це відчуває себе особливо погано, оскільки ітератори квазіфункціонально співвідносяться із вмістом файлу, але керування ручками файлів - це зовсім окреме завдання. Збивання обох, непомітно, в одну дію, дивує людей, які читають код і ускладнює міркування про поведінку програми.
Інші мови, по суті, дійшли такого ж висновку. Haskell ненадовго фліртував з так званим "ледачим IO", який дозволяє вам повторювати файл і автоматично закривати його, коли ви добираєтесь до кінця потоку, але майже всезаблуджено використовувати лінивий IO в Haskell в ці дні та Haskell Користувачі в основному перейшли до більш чіткого управління ресурсами, як Conduit, який веде себе більше як withблок в Python.
На технічному рівні, можливо, ви захочете виконати обробку файлів у Python, яка не спрацювала б, якби ітерація закрила обробку файлу. Наприклад, припустимо, що мені потрібно повторити файл два рази:
with open('filename.txt') as fp:
for line in fp:
...
fp.seek(0)
for line in fp:
...
Хоча це менш поширений випадок використання, врахуйте той факт, що я, можливо, щойно додав три рядки коду внизу до існуючої бази коду, яка спочатку мала три верхні рядки. Якби ітерація закрила файл, я б не змогла це зробити. Таким чином, зберігаючи ітерацію та управління ресурсами окремо, це простіше складати шматки коду у більшу, працюючу програму Python.
Композиційність - одна з найважливіших функцій використання мови чи API.