открыть, прочитать и закрыть файл в 1 строчке кода

129

Сейчас использую:

pageHeadSectionFile = open('pagehead.section.htm','r')
output = pageHeadSectionFile.read()
pageHeadSectionFile.close()

Но чтобы код выглядел лучше, я могу:

output = open('pagehead.section.htm','r').read()

Как при использовании указанного выше синтаксиса закрыть файл, чтобы освободить системные ресурсы?

1qazxsw2
источник
19
В однострочниках нет ничего более привлекательного. Код читают гораздо чаще, чем пишут, и его следует писать для понимания, а не для «хладнокровия». Единственное исключение - это когда в языке есть хорошо известная идиома, но я не знаю ее в данном случае.
drdwilcox
17
@drdwilcox: Скрытые однострочники - это плохо, декларативные однострочные - это хорошо. Нет причины (по крайней мере, я не вижу ее), почему в ядре нет функции-оболочки для чтения файла (такая общая необходимость) за один вызов функции. Что-то вроде contents = os.readfile(path). Если бы я хотел сделать что-то более интересное, то хорошо, я бы с радостью использовал with open(path) as fd: contents = fd.read(). Конечно, можно написать свою собственную оболочку, но для этого предназначено ядро, чтобы предоставить программистам полезные абстракции.
tokland
5
Верно, что код читается гораздо чаще, чем пишется, но вывод о том, что более длинный код так же хорош, как и короткий, не может быть более неправильным. Если вы потратите время на то, чтобы сделать свой код как можно короче (не прибегая к хитрым приемам, которые трудно понять), эти вложения окупятся снова и снова, когда код будет прочитан. Каждая строка, которую вы пишете, оказывает медвежью услугу любому, кто читает ваш код, поэтому вам следует стремиться писать как можно меньше. Вспомните знаменитую цитату Паскаля: «Я сделал это письмо длиннее только потому, что у меня не было времени сделать его короче».
Джон Уильямс,

Ответы:

195

Вам действительно не нужно закрывать его - Python сделает это автоматически либо во время сборки мусора, либо при выходе из программы. Но, как заметил @delnan, лучше явно закрыть его по разным причинам.

Итак, что вы можете сделать, чтобы он был кратким, простым и ясным:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Теперь это всего две строчки, и я думаю, они довольно читабельны.

Тим Пицкер
источник
2
@ 1qazxsw2 Если вы используете withоператор, файловый ресурс будет закрыт для вас правильно.
Дэвид Альбер
13
По поводу первого предложения: Python в конце концов закроет его . Но это не значит, что вы должны забыть о закрытии. Даже при реф-подсчете файл может оставаться открытым намного дольше, чем вы думаете и хотите (например, если на него ссылаются циклами). Это происходит трижды в реализациях Python, которые имеют приличный сборщик мусора, где у вас нет гарантии, что что-то будет сборщиком мусора в любой конкретный момент. Даже в документации CPython говорится, что вам не следует полагаться на сборку мусора для подобной очистки. Последняя часть ответа должна быть жирной.
6
Если вам действительно нужен однострочник , можно разместить output = f.read()часть на той же строке после :.
Карл Кнехтель
1
"открыть, прочитать и закрыть файл в 1 строчке кода" это две строчки и не отвечает на вопрос.
user5359531
1
Это зависит от реализации - см. Ответ Свена.
Тим Пицкер
72

Модуль Pathlib стандартной библиотеки Python делает то, что вы ищете:

Path('pagehead.section.htm').read_text()

Не забудьте импортировать Path:

jsk@dev1:~$ python3
Python 3.5.2 (default, Sep 10 2016, 08:21:44)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from pathlib import Path
>>> (Path("/etc") / "hostname").read_text()
'dev1.example\n'

На Python 27 установите backported pathlibилиpathlib2

Януш Сконечны
источник
8
Предлагаемые другие ответы withхороши, но withэто утверждение, а не выражение. Этот pathlibответ - единственный ответ на исходный вопрос, который можно встроить в выражение Python. Что-то вродеSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael
24

Используя CPython, ваш файл будет закрыт сразу после выполнения строки, потому что файловый объект немедленно удаляется сборщиком мусора. Однако есть два недостатка:

  1. В реализациях Python, отличных от CPython, файл часто закрывается не сразу, а позже, вне вашего контроля.

  2. В Python 3.2 или более поздних версиях это вызовет ошибку ResourceWarning, если она включена.

Лучше вложить одну дополнительную линию:

with open('pagehead.section.htm','r') as f:
    output = f.read()

Это гарантирует правильное закрытие файла при любых обстоятельствах.

Свен Марнах
источник
17

Для этого не нужно импортировать какие-либо специальные библиотеки.

Используйте обычный синтаксис, и он откроет файл для чтения, а затем закроет его.

with open("/etc/hostname","r") as f: print f.read() 

или

with open("/etc/hosts","r") as f: x = f.read().splitlines()

который дает вам массив x, содержащий строки, и может быть напечатан так:

for line in x: print line

Эти однострочные сообщения очень полезны для обслуживания - в основном самодокументируются.

SDsolar
источник
8

Что вы можете сделать, так это использовать withоператор и написать два шага в одной строке:

>>> with open('pagehead.section.htm', 'r') as fin: output = fin.read();
>>> print(output)
some content

withЗаявление будет заботиться , чтобы вызова __exit__функции данного объекта , даже если что - то плохое случилось в вашем коде; это близко к try... finallyсинтаксису. Для объекта, возвращенного open, __exit__соответствует закрытию файла.

Этот оператор был введен в Python 2.6.

Жоэль
источник
Небольшое уточнение: согласно документации with был введен в Python 2.5, но должен был быть явно импортирован из __future__. Он стал доступен во всех контекстах Python 2.6.
Дэвид Альбер
5

используйте ilio : (inline io):

только один вызов функции вместо файлов open (), read (), close ().

from ilio import read

content = read('filename')
иман
источник
3

Я думаю, что наиболее естественный способ добиться этого - определить функцию.

def read(filename):
    f = open(filename, 'r')
    output = f.read()
    f.close()
    return output

Тогда вы можете сделать следующее:

output = read('pagehead.section.htm')
Адриен Павао
источник
2
with open('pagehead.section.htm')as f:contents=f.read()

источник
4
Чем это отличается от трех основных ответов?
Все рабочие
4
Самая большая разница в том, что это только одна строка, как указано в вопросе. Лично я не могу найти ничего, кроме этого, но не стесняйтесь критиковать мою работу, а не самостоятельно отвечать на вопрос.
3
Самый короткий, встроенный способ открыть, прочитать и закрыть файл в Python - это использовать 2 логические строки, независимо от того, сжаты ли они до 1 строки или нет. Поэтому я не думаю, что этот ответ будет эффективно отличаться от трех исходных ответов.
Все рабочие
1
Неважно, отличается ли он «эффективно». Я попал на эту страницу в поисках однострочного синтаксиса, который можно было бы использовать python -cв командной строке, поэтому публикация двухстрочных ответов не помогает.
user5359531
1
@ user5359531 Я не понимаю, что вы думаете: знаете ли вы, что вы можете цитировать выражения Python с помощью ", использовать ;для добавления двух инструкций и удаления новой строки после :? Следующее выражение отлично подходит для меня:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël
0

Я часто делаю что-то подобное, когда мне нужно получить несколько строк, окружающих то, что я нашел в файле журнала:

$ grep -n "xlrd" requirements.txt | awk -F ":" '{print $1}'
54

$ python -c "with open('requirements.txt') as file: print ''.join(file.readlines()[52:55])"
wsgiref==0.1.2
xlrd==0.9.2
xlwt==0.7.5
Мэтью Пёрдон
источник
1
Совершенно никакого отношения к первоначальной теме, но вы должны смотреть на grep -A <n>, grep -B <n>и grep -C <n>, если это полезно. Дополнительная информация: stackoverflow.com/a/9083/1830159
Лиам Стэнли,
0

Используя more_itertools.with_iter, можно открывать, читать, закрывать и назначать эквивалент outputв одной строке (исключая оператор импорта):

import more_itertools as mit


output = "".join(line for line in mit.with_iter(open("pagehead.section.htm", "r")))

Хотя это возможно, я бы поискал другой подход, отличный от присвоения содержимого файла переменной, то есть ленивую итерацию - это можно сделать с помощью традиционного withблока или, в приведенном выше примере, путем удаления join()и повторения output.

pylang
источник
Вы также можете импортировать внутри oneliner. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Это отлично работает и устраняет необходимость в строке для импорта.
melwil 01
1
Я полностью с вами согласен. Однако, обсуждая решение задач с помощью одинарных инструкций, я часто сталкивался с аргументами, в которых согласованным результатом должна быть одна строка кода, вставленная в новую оболочку Python. Такие вызовы редко соответствуют pep8. Это никоим образом не является хорошей практикой для написания кода, это было всего лишь советом по устранению необходимости в импорте.
melwil
0

Если вы хотите , чтобы тепло и нечеткое чувство просто пойти с с .

Для python 3.6 я запустил эти две программы с новым запуском IDLE, получив время выполнения:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Так что особой разницы нет.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test A for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: A: no 'with;
    c=[]
    start_time = time.time()
    c = open(inTextFile).read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

ВЫВОД:

OK, starting program...
--- 0.002000093460083008 seconds ---
OK, program execution has ended.

#--------*---------*---------*---------*---------*---------*---------*---------*
# Desc: Test B for reading a text file line-by-line into a list
#--------*---------*---------*---------*---------*---------*---------*---------*

import sys
import time

#                                  # MAINLINE
if __name__ == '__main__':
    print("OK, starting program...")

    inTextFile = '/Users/Mike/Desktop/garbage.txt'

#                                  # Test: B: using 'with'
    c=[]
    start_time = time.time()
    with open(inTextFile) as D: c = D.read().splitlines()
    print("--- %s seconds ---" % (time.time() - start_time))

    print("OK, program execution has ended.")
    sys.exit()                     # END MAINLINE

ВЫВОД:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
CopyPasteIt
источник