buka baca dan tutup file dalam 1 baris kode

128

Sekarang saya menggunakan:

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

Tetapi untuk membuat kode terlihat lebih baik, saya dapat melakukan:

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

Saat menggunakan sintaks di atas, bagaimana cara menutup file untuk membebaskan sumber daya sistem?

1qazxsw2
sumber
19
Tidak ada yang secara inheren lebih menarik dari one-liners. Kode dibaca jauh lebih sering daripada yang tertulis, dan harus ditulis untuk pemahaman, bukan untuk "kesejukan." Satu-satunya pengecualian adalah ketika ada idiom terkenal dalam suatu bahasa, tetapi saya tidak mengetahui satu dalam hal ini.
drdwilcox
17
@drdwilcox: Cryptic one-liners buruk, deklaratif satu-liner bagus. Tidak ada alasan (setidaknya saya tidak bisa melihatnya), mengapa tidak ada fungsi wrapper di inti untuk membaca file (kebutuhan umum seperti itu) dalam satu panggilan fungsi. Sesuatu seperti contents = os.readfile(path). Jika saya ingin melakukan sesuatu yang lebih menarik, maka ok, saya dengan senang hati akan menggunakannya with open(path) as fd: contents = fd.read(). Tentu saja orang dapat menulis pembungkusnya sendiri, tetapi untuk itulah intinya, untuk memberikan manfaat bagi abstraksi bagi para programmer.
tokland
5
Memang benar bahwa kode dibaca jauh lebih banyak daripada yang tertulis, tetapi implikasi bahwa kode yang lebih panjang sama baiknya dengan kode pendek tidak bisa lebih salah. Jika Anda menginvestasikan waktu untuk membuat kode sesingkat mungkin (tanpa menggunakan trik pintar yang sulit dipahami), investasi itu akan terbayar berulang ketika kode dibaca. Setiap baris yang Anda tulis adalah merugikan siapa pun yang membaca kode Anda, jadi Anda harus berusaha untuk menulis sesedikit mungkin. Ingat kutipan terkenal dari Pascal: "Saya membuat surat ini lebih lama hanya karena saya tidak memiliki waktu luang untuk membuatnya lebih pendek."
John Williams

Jawaban:

195

Anda tidak benar-benar harus menutupnya - Python akan melakukannya secara otomatis saat pengumpulan sampah atau saat keluar dari program. Tapi seperti yang dicatat @delnan, lebih baik berlatih untuk menutupnya secara eksplisit karena berbagai alasan.

Jadi, apa yang dapat Anda lakukan agar singkat, sederhana, dan eksplisit:

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

Sekarang hanya dua baris dan cukup mudah dibaca, saya pikir.

Tim Pietzcker
sumber
2
@ 1qazxsw2 Jika Anda menggunakan withpernyataan , sumber daya file akan ditutup dengan benar untuk Anda.
David Alber
13
Re kalimat pertama: Python akhirnya akan menutupnya . Tetapi itu tidak berarti Anda harus melupakan tentang penutupan. Bahkan dengan penghitungan ulang, file mungkin tetap terbuka jauh lebih lama daripada yang Anda pikirkan dan inginkan (misalnya jika kebetulan dirujuk oleh siklus). Ini berlaku tiga kali dalam implementasi Python yang memiliki GC yang layak, di mana Anda tidak memiliki jaminan bahwa ada yang GC pada waktu tertentu. Bahkan dokumentasi CPython mengatakan Anda tidak harus bergantung pada GC untuk pembersihan seperti ini. Bagian terakhir dari jawaban harus tebal.
6
Jika Anda benar-benar membutuhkan satu-liner , dimungkinkan untuk meletakkan output = f.read()bagian pada baris yang sama setelah :.
Karl Knechtel
1
"buka baca dan tutup file dalam 1 baris kode" ini adalah dua baris, dan tidak menjawab pertanyaan.
user5359531
1
Itu tergantung implementasi - lihat jawaban Sven.
Tim Pietzcker
71

Modul Python Standard Library Pathlib melakukan apa yang Anda cari:

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

Jangan lupa untuk mengimpor 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'

Pada Python 27 instal backported pathlibataupathlib2

Janusz Skonieczny
sumber
8
Jawaban lain yang diajukan withbaik-baik saja, tetapi withmerupakan pernyataan, bukan ekspresi. pathlibJawaban ini adalah satu-satunya jawaban untuk pertanyaan asli yang dapat disematkan dalam ekspresi Python. Sesuatu sepertiSECRET_KEY = os.environ.get('SECRET_KEY') or pathlib.Path('SECRET_KEY').read_bytes()
LeoRochael
24

Menggunakan CPython, file Anda akan ditutup segera setelah baris dieksekusi, karena objek file segera dikumpulkan sampah. Namun ada dua kelemahan:

  1. Dalam implementasi Python yang berbeda dari CPython, file seringkali tidak langsung ditutup, tetapi di lain waktu, di luar kendali Anda.

  2. Dalam Python 3.2 atau lebih tinggi, ini akan melempar a ResourceWarning, jika diaktifkan.

Lebih baik menginvestasikan satu baris tambahan:

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

Ini akan memastikan bahwa file ditutup dengan benar dalam semua keadaan.

Sven Marnach
sumber
17

Tidak perlu mengimpor perpustakaan khusus untuk melakukan ini.

Gunakan sintaksis normal dan itu akan membuka file untuk dibaca kemudian tutup.

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

atau

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

yang memberi Anda array x yang berisi garis-garis, dan dapat dicetak seperti ini:

for line in x: print line

One-liner ini sangat membantu untuk pemeliharaan - pada dasarnya mendokumentasikan diri.

SDsolar
sumber
8

Yang dapat Anda lakukan adalah menggunakan withpernyataan itu, dan menulis dua langkah pada satu baris:

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

The withpernyataan akan mengurus panggilan __exit__fungsi dari objek yang diberikan bahkan jika sesuatu yang buruk terjadi dalam kode Anda; dekat dengan try... finallysintaks. Untuk objek yang dikembalikan oleh open, __exit__terkait dengan penutupan file.

Pernyataan ini telah diperkenalkan dengan Python 2.6.

Joël
sumber
Klarifikasi kecil: menurut dokumentasi with diperkenalkan dalam Python 2.5, tetapi harus secara eksplisit diimpor dari __future__. Itu menjadi tersedia dari semua konteks di Python 2.6.
David Alber
5

gunakan ilio : (inline io):

hanya satu panggilan fungsi alih-alih file buka (), baca (), tutup ().

from ilio import read

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

sumber
4
Bagaimana ini berbeda dari 3 jawaban teratas?
Semua Pekerja Penting
4
Perbedaan terbesar adalah bahwa itu hanya satu baris seperti pertanyaan yang ditentukan. Secara pribadi saya tidak dapat menemukan lebih dari itu tetapi merasa bebas untuk mengkritik pekerjaan saya daripada benar-benar berkontribusi pada pertanyaan Anda sendiri.
3
Cara terpendek, bawaan untuk mencapai membuka, membaca, dan menutup file dengan Python adalah menggunakan 2 baris logis apakah itu diringkas menjadi 1 baris atau tidak. Jadi saya tidak melihat jawaban ini secara efektif berbeda dari 3 jawaban asli.
Semua Pekerja Penting
1
Tidak masalah jika 'efektif' berbeda. Saya sampai di halaman ini untuk mencari sintaks satu-baris yang mungkin digunakan dengan python -cpada baris perintah, jadi memposting jawaban 2-baris tidak membantu.
user5359531
1
@ user5359531 Saya tidak mengerti maksud Anda: tahukah Anda bahwa Anda dapat mengutip ekspresi python ", gunakan ;untuk menambahkan dua instruksi, dan menghapus baris baru setelahnya :? Ekspresi berikut berfungsi dengan baik untuk saya:$> python -c "with open('some file', 'r') as f: print(next(f))"
Joël
2

Saya pikir cara paling alami untuk mencapai ini adalah dengan mendefinisikan suatu fungsi.

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

Maka Anda dapat melakukan hal berikut:

output = read('pagehead.section.htm')
Adrien Pavao
sumber
0

Saya sering melakukan sesuatu seperti ini ketika saya perlu mendapatkan beberapa baris di sekitar sesuatu yang saya ambil dalam file log:

$ 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
Matthew Purdon
sumber
1
Sama sekali tidak berhubungan dengan topik asli, tapi Anda harus melihat ke dalam grep -A <n>, grep -B <n>dan grep -C <n>, jika membantu. Info lebih lanjut: stackoverflow.com/a/9083/1830159
Liam Stanley
0

Dengan menggunakan more_itertools.with_iter, dimungkinkan untuk membuka, membaca, menutup, dan menetapkan yang setara outputdalam satu baris (tidak termasuk pernyataan impor):

import more_itertools as mit


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

Meskipun mungkin, saya akan mencari pendekatan lain selain menugaskan konten file ke variabel, yaitu iterasi malas - ini dapat dilakukan dengan menggunakan withblok tradisional atau dalam contoh di atas dengan menghapus join()dan mengulangi output.

pylang
sumber
Anda dapat mengimpor di dalam oneliner juga. "".join(line for line in __import__('more_itertools').with_iter(open("pagehead.section.htm", "r")))Ini berfungsi dengan baik, dan menghilangkan kebutuhan untuk jalur impor.
melwil
1
Saya sepenuhnya setuju dengan Anda. Namun ketika membahas tugas penyelesaian dengan oneliners, saya sering menemukan diri saya dalam argumen di mana hasil yang disepakati harus menjadi satu baris kode yang disisipkan ke shell python baru. Tantangan seperti itu jarang sesuai dengan pep8. Ini sama sekali bukan praktik yang baik untuk menulis kode, itu hanya dimaksudkan sebagai tip untuk menghilangkan kebutuhan impor.
melwil
0

Jika Anda ingin yang hangat dan kabur perasaan hanya pergi dengan dengan .

Untuk python 3.6 saya menjalankan kedua program ini di bawah IDLE yang baru dimulai, memberikan runtime dari:

0.002000093460083008  Test A
0.0020003318786621094 Test B: with guaranteed close

Jadi tidak banyak perbedaan.

#--------*---------*---------*---------*---------*---------*---------*---------*
# 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

KELUARAN:

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

KELUARAN:

OK, starting program...
--- 0.0020003318786621094 seconds ---
OK, program execution has ended.
CopyPasteIt
sumber