2012-08-22 3 views
0

Предположим, у меня есть файл test.txt и вы хотите распечатать его. Я мог бы это сделать, как это в Python (это просто пример, чтобы проиллюстрировать мой вопрос, не пример хорошего кода):Файлы закрываются после оценки выражения генератора

for i in (line for line in open('test.txt')): 
    print ">", i, 

Я использовал strace, чтобы убедиться, что файл открыт и закрыт после кода выполнил.

Вопрос: Почему файл закрыт? Я предполагаю, что это имеет какое-то отношение к менеджерам контекста, но я не могу найти ссылку на этот тип конструкции и почему файл автоматически закрывается. Кто знает, что происходит именно за кулисами и может это объяснить?

ответ

3

Когда ссылка на файл выходит за пределы области видимости, это сбор мусора и закрыт как часть удаления. Поскольку вы не назначаете файл имени, как только цикл заканчивается, он выходит за рамки. Это, однако, не очень хорошо опираться. Используйте реальный менеджер контекста вместо этого, например:

with open('test.txt') as f: 
    for i in f: 
     print(">", i, end="") 

Это также стоит отметить, ваше выражение генератор ничего не делает здесь, так что я удалил его.

+0

Да, я знаю, что 'with ...:' существует. Вопрос в том, где это упоминается в документах: -> Кроме того, почему я не могу полагаться на то, что он автоматически закрывается, если он выходит за рамки? – hochl

+0

@hochl Нет спецификации относительно того, как сбор мусора должен работать в Python. CPython делает это путем подсчета ссылок, но другие реализации могут делать это другими способами, производя разные результаты. Это также может означать, что файл не получается корректно, если у вас есть исключение. Однако самая большая причина - читаемость. Оператор 'with' делает ваше закрытие файла явным, что намного читаемо и меньше подвержено ошибкам. –

+0

@hochl, потому что что вы ожидаете, когда объект выходит за рамки? Остаться в живых? Он становится помеченным для уничтожения и для файла, закрывая его, является частью процесса жизненного цикла. –

1

См. this answer. Вы не держите ссылку на файл-объект, поэтому после запуска цикла он не имеет ссылок на него. Затем происходит сбор мусора, и когда это происходит, файл закрывается. Тем не менее, нет никакой гарантии, что это будет сбор мусора сразу после цикла. Некоторое время он мог сидеть, прежде чем Python замечает, что он не используется. Из-за этого лучше явно закрыть файл или, что еще лучше, использовать блок with, чтобы он закрывался для вас.

+0

Ах, правильно! Интересно, что все тестовые примеры сразу закрыли файл, но тогда это поведение просто чистое совпадение и не гарантировано. Угадайте, что оба ответа будут качества для принятия. – hochl

+0

Правильно, он всегда может это сделать для вас, но дело в том, что вы не можете полагаться на это, работая на кого-то другого, возможно, запуская другую версию Python (возможно, будущую версию, которая еще не существует). – BrenBarn

+1

Ваши тестовые примеры, по-видимому, все запущены в CPython, который всегда будет немедленно закрыт из-за подсчета GC. В других реализациях это будет варьироваться в широких пределах. Удаление объектов выполняется, чтобы освободить место, если вы используете его для выполнения чего-то другого, это плохая идея. –

Смежные вопросы