продолжительность Python для файлового объекта в списке аргументов - PullRequest
2 голосов
/ 23 марта 2010

В документации для модуля рассола есть фрагмент кода примера:

reader = pickle.load(open('save.p', 'rb'))

, который при первом чтении выглядел так, как если бы он выделил дескриптор системного файла, прочитал его содержимое и затем «утек» в открытый дескриптор, потому что нет дескриптора, доступного для вызова close(). Это заставило меня задуматься, есть ли какая-то скрытая магия, которая позаботится об этом случае.

Окунувшись в источник, я обнаружил в Modules / _fileio.c, что файловые дескрипторы закрыты деструктором fileio_dealloc (), что привело к реальному вопросу.

Какова продолжительность использования файлового объекта в приведенном выше примере кода? После выполнения этого оператора действительно ли объект становится не связанным, и, следовательно, будет ли fd подвергаться действительному вызову close(2) при некоторой последующей очистке сборки мусора? Если да, то является ли пример строк хорошей практикой или не следует рассчитывать на освобождение fd, что может привести к исчерпанию таблицы дескрипторов ядра для каждого процесса?

1 Ответ

3 голосов
/ 23 марта 2010

Какова длительность файла объект, возвращаемый кодом примера выше

Этот код не возвращает объект файла (как правильно говорит заголовок Q, он получает его в качестве аргумента).

В текущем CPython файл будет закрыт во время возврата функции (поскольку функция не прячет ссылки на объект файла в более надежные места). В других реализациях файл будет закрыт "в конце концов", но точное время не указано.

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

Скорее, лучше всего использовать выражение with:

with open(...) as f:
  reader = pickle.load(f)

При использовании при немедленное закрытие файла (как только заканчивается тело оператора with) гарантируется во всех реализациях.

Обратите внимание, что в Python 2.5 вам нужно from __future__ import with_statement, чтобы использовать with. В версии 2.6 или выше такой «импорт из будущего» не требуется для этой цели (это безобидно, но если вы знаете, что никогда не собираетесь использовать версию 2.5, она избыточна и лучше удалена).

...