Чи важливо явне закриття файлів?


149

Якщо в Python ви відкриваєте файл без виклику close(), або закриваєте файл, але не використовуєте try- finallyабо " with", це проблема? Або як практика кодування достатньо покластися на збирання сміття Python для закриття всіх файлів? Наприклад, якщо хтось робить це:

for line in open("filename"):
    # ... do stuff ...

... це проблема, тому що файл ніколи не можна закрити, і може статися виняток, який заважає закрити його? Або він обов'язково буде закритий після завершення forзаяви, оскільки файл виходить за межі області?


13
Файл не виходить за рамки в кінці forблоку. Його посилання буде нульовим, що призведе до автоматичного закриття, але лише функції, класи та модулі визначають області застосування в Python, а не інші складні оператори.
agf

18
Це не проблема, якщо це не проблема. На рівні ОС будь-які файли, відкриті скриптом, будуть закриті, коли сценарій закінчується, тому вам не потрібно турбуватися про закриття файлів у сценаріях інструментів, що викидаються. Однак процеси мають обмеження щодо кількості відкритих файлів, які вони можуть підтримувати, тому довгоживучі або складні сценарії, можливо, повинні бути обережнішими. У будь-якому випадку, це корисна звичка закривати свої файли.
Рассел Борогов,

3
@agf: Ви маєте рацію, що файл не виходить за рамки, але це не пов’язано з розмежуванням між forблоками та функціями / класами / модулями. Це набагато простіше, ніж це: об’єкти не мають масштабів, а лише імена. Немає імені, яке б посилалося на цей об’єкт, тому тут немає нічого, щоб не залишатися в межах сфери дії та не виходити за межі її дії.
макс

@max Мій коментар виправляє його припущення про те, що існує область, пов'язана з forциклом, і згадується, що файл закривається з зовсім іншої причини. Він не потрапляє у сфери застосування Python, оскільки це не доречно.
agf

@max є неявна посилання на це для циклу ... це аргумент семантики
Петро R

Відповіді:


126

У вашому прикладі файл не гарантовано буде закритий до виходу перекладача. У поточних версіях CPython файл буде закритий в кінці циклу for, оскільки CPython використовує підрахунок посилань як свій основний механізм збору сміття, але це деталізація реалізації, а не особливість мови. Інші реалізації Python не гарантовано працюють таким чином. Наприклад, IronPython, PyPy та Jython не використовують підрахунок посилань і тому не закриють файл у кінці циклу.

Погана практика покладатися на реалізацію сміття CPython, оскільки це робить ваш код менш портативним. Можливо, у вас не буде витоків ресурсів, якщо ви використовуєте CPython, але якщо ви коли-небудь переходите на реалізацію Python, яка не використовує підрахунку посилань, вам потрібно буде пройти весь код і переконатися, що всі ваші файли закриті належним чином.

Для вашого прикладу використовуйте:

with open("filename") as f:
     for line in f:
        # ... do stuff ...

8
Чи with open() as fавтоматично закриває файл після його завершення?
Рохан

24
@Rohan так, це маленька магія, яку надає withоператор, але звичайно, щоб ця магія працювала на об'єкті, повинні бути спеціальні методи, __enter__і __exit__в останньому об'єкт робить closeі будь-які інші речі очищення, які потрібно зробити в кінець withзаяви ...
Копперфілд

1
FYI: Ця відповідь пояснює лише "коли вона буде закрита", але не пояснює "що робити, якщо вона залишається відкритою". Для останнього, будь ласка, прочитайте "Що буде, якщо файл залишиться відкритим?" участь у цій відповіді ( askubuntu.com/questions/701491/… )
RayLuo

Більше того, не закриття файлів може призвести до урізання файлів, оскільки вміст файлу не змито.
Ерван Легранд

Тож якщо я не закрию файл, чи поверну пам'ять напевно, як тільки програма перестане працювати? Або мені насправді доведеться вийти з усього перекладача?
Pro Q

22

Деякі пітони закриватимуть файли автоматично, коли на них більше не посилаються, в той час як інші - ні, і O / S - це закрити файли, коли інтерпретатор Python закриється.

Навіть для пітонів, які закриють файли для вас, час не гарантується: це може бути негайно, або пізніше це можуть бути секунди / хвилини / години / дні.

Тож, хоча у вас можуть не виникати проблем із Python, який ви використовуєте, напевно, це не найкраща практика залишати свої файли відкритими. Насправді в cpython 3 ви отримаєте попередження про те, що система повинна була закрити файли, якщо ви цього не робили.

Мораль: Прибирайте за собою. :)


9
Файли закриваються, коли на CPython вони більше не посилаються, але це не мовна функція. Якби це було, ви могли б із задоволенням покластися на нього.
Пітер Грем

9

Хоча використовувати таку конструкцію в цьому конкретному випадку цілком безпечно, є деякі застереження для узагальнення такої практики:

  • run потенційно може не вистачати дескрипторів файлів, хоча малоймовірно, уявіть собі полювання на помилку
  • можливо, ви не зможете видалити згаданий файл у деяких системах, наприклад, win32
  • якщо ви запускаєте щось, крім CPython, ви не знаєте, коли файл закриється для вас
  • якщо ви відкриєте файл у режимі запису чи читання-запису, ви не знаєте, коли дані змиваються

3

У файлі збирається сміття, а значить, закривається. GC визначає, коли він закривається, а не ти. Очевидно, це не рекомендована практика, оскільки ви можете натиснути ліміт відкритої обробки файлів, якщо не закриєте файли, як тільки закінчите їх використовувати. Що робити, якщо в межах forвашого циклу ви відкриєте більше файлів і залишите їх затриманими?


Але якщо ви відкрили інші файли, що знаходяться в циклі для циклу, все одно буде відкрито більше одного файлу одночасно, незалежно від того, закриваєте ви будь-який з них чи ні. Ви хочете сказати, що файл не обов’язково збирається сміттям, як тільки файл виходить із сфери застосування, таким чином він буде закритий швидше, якщо це буде зроблено явно? А як щодо випадків, коли відбувається виняток (коли ви використовуєте з / спробувати нарешті проти цього не робити)?
користувач553702

1
У CPython підрахунок посилань призведе до того, що він буде зібраний після forзаяви - вам не доведеться чекати наступного запуску сміття.
agf

3

Привіт Дуже важливо закрити дескриптор файлів у ситуації, коли ви збираєтесь використовувати його вміст у тому ж сценарії python. Я сьогодні сам усвідомлюю після такої тривалої налагоджувальної роботи. Причина полягає в тому, що вміст буде відредаговано / видалено / збережено лише після закриття дескриптора файлів, і зміни стосуються файлу!

Отже, припустимо, у вас є ситуація, коли ви записуєте вміст у новий файл, а потім, не закриваючи fd, ви використовуєте цей файл (не fd) в іншій команді оболонки, яка читає його вміст. У цій ситуації ви не отримаєте вміст для команди оболонки, як очікувалося, і якщо ви спробуєте налагодити, ви не зможете легко знайти помилку. ви також можете прочитати більше у моєму записі в блозі http://magnificentzps.blogspot.in/2014/04/importance-of-closing-file-descriptor.html


1

Під час процесу вводу / виводу дані буферуються: це означає, що вони зберігаються у тимчасовому місці перед тим, як записати у файл.

Python не змиває буфер, тобто записує дані у файл, поки не буде впевнений, що ви закінчили писати. Один із способів зробити це - закрити файл.

Якщо ви пишете у файл без закриття, дані не перетворять його у цільовий файл.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.