відкрити читання та закрити файл у 1 рядку коду


128

Зараз я використовую:

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

Але щоб код виглядав краще, я можу:

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

Як використовувати вищевказаний синтаксис, як закрити файл, щоб звільнити системні ресурси?


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
Re першого речення: Python буде закрити його в кінці кінців . Але це не означає, що ви повинні забути про закриття. Навіть при перерахунку рахунків файл може залишатися відкритим набагато довше, ніж ви думаєте та хочете (наприклад, якщо воно трапляється циклами). Це тричі в реалізації Python, які мають пристойний GC, де ви не маєте гарантії, що GC'd нічого не буде в будь-який конкретний час. Навіть документація CPython говорить, що ви не повинні покладатися на GC для такого очищення. Остання частина відповіді повинна бути жирною.

6
Якщо вам дійсно потрібен один вкладиш , можна поставити output = f.read()частину на одній і тій же лінії , після того :.
Карл Кнечтел

1
"відкрити читання і закрити файл в 1 рядку коду" це два рядки, і це не відповідає на запитання.
користувач5359531

1
Від цього залежить реалізація - див. Відповідь Свена.
Тім Піцкер

71

Модуль Pathlib стандартної бібліотеки Python робить те, що ви шукаєте:

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

Не забудьте імпортувати Шлях:

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 встановіть підтримуваний 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 або новіших версій це буде кидати a 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

Ці однокласники дуже корисні для обслуговування - в основному самостійно документуючи.


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 : (вбудований io):

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

from ilio import read

content = read('filename')

2
with open('pagehead.section.htm')as f:contents=f.read()

4
Чим це відрізняється від топ-3 відповідей?
Усі працівники найважливіші

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

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

1
Не має значення, чи є його "ефективно" іншим. Я потрапив на цю сторінку, шукаючи однорядковий синтаксис, який може використовуватися python -cв командному рядку, тому розміщення дворядкових відповідей не допомагає.
користувач5359531

1
@ user5359531 Я не бачу вашої точки зору: чи знаєте ви, що ви можете цитувати вирази python за "допомогою ;додавання двох інструкцій та видалення нового рядка після :? Наступний вираз для мене працює чудово:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël

2

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

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

Тоді ви можете зробити наступне:

output = read('pagehead.section.htm')

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.


Ви також можете імпортувати всередині oneliner. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Це працює чудово і виключає необхідність у рядку для імпорту.
melwil

1
Я повністю з вами згоден. Однак, обговорюючи рішення завдань з oneliners, я часто опинявся в аргументах, коли узгоджений результат повинен бути єдиним рядком коду, вставленим у свіжу оболонку пітона. Такі виклики рідко відповідають 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.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.