Cara membuka file menggunakan pernyataan terbuka dengan

200

Saya sedang mencari cara melakukan input dan output file dengan Python. Saya telah menulis kode berikut untuk membaca daftar nama (satu per baris) dari file ke file lain sambil memeriksa nama terhadap nama-nama dalam file dan menambahkan teks ke kejadian dalam file. Kode berfungsi. Bisakah itu dilakukan lebih baik?

Saya ingin menggunakan with open(...pernyataan untuk file input dan output tetapi tidak bisa melihat bagaimana mereka bisa berada di blok yang sama yang berarti saya harus menyimpan nama-nama di lokasi sementara.

def filter(txt, oldfile, newfile):
    '''\
    Read a list of names from a file line by line into an output file.
    If a line begins with a particular name, insert a string of text
    after the name before appending the line to the output file.
    '''

    outfile = open(newfile, 'w')
    with open(oldfile, 'r', encoding='utf-8') as infile:
        for line in infile:
            if line.startswith(txt):
                line = line[0:len(txt)] + ' - Truly a great person!\n'
            outfile.write(line)

    outfile.close()
    return # Do I gain anything by including this?

# input the name you want to check against
text = input('Please enter the name of a great person: ')    
letsgo = filter(text,'Spanish', 'Spanish2')
Disnami
sumber
"artinya aku harus menyimpan nama-nama itu di lokasi sementara"? Bisakah Anda menjelaskan apa yang Anda maksudkan dengan ini?
S.Lott
4
Perhatikan bahwa itu filter()adalah fungsi bawaan sehingga Anda mungkin harus memilih nama yang berbeda untuk fungsi Anda.
Tom
2
@ Tom apakah fungsi di namespace mengesampingkan fungsi bawaan?
UpTide
2
@ UpTide: Ya, Python beroperasi dalam urutan LEGB - Lokal, Melampirkan, Global, Built-in (lihat stackoverflow.com/questions/291978/… ). Jadi, jika Anda membuat fungsi global ( filter()), itu akan ditemukan sebelum built-infilter()
Tom

Jawaban:

308

Python memungkinkan menempatkan banyak open()pernyataan dalam satu with. Anda pisahkan mereka. Kode Anda akan menjadi:

def filter(txt, oldfile, newfile):
    '''\
    Read a list of names from a file line by line into an output file.
    If a line begins with a particular name, insert a string of text
    after the name before appending the line to the output file.
    '''

    with open(newfile, 'w') as outfile, open(oldfile, 'r', encoding='utf-8') as infile:
        for line in infile:
            if line.startswith(txt):
                line = line[0:len(txt)] + ' - Truly a great person!\n'
            outfile.write(line)

# input the name you want to check against
text = input('Please enter the name of a great person: ')    
letsgo = filter(text,'Spanish', 'Spanish2')

Dan tidak, Anda tidak mendapatkan apa pun dengan menempatkan eksplisit returndi akhir fungsi Anda. Anda dapat menggunakan returnuntuk keluar lebih awal, tetapi Anda memilikinya di akhir, dan fungsinya akan keluar tanpa itu. (Tentu saja dengan fungsi yang mengembalikan nilai, Anda menggunakan returnuntuk menentukan nilai yang akan dikembalikan.)

Menggunakan banyak open()item dengan withtidak didukung dalam Python 2.5 saat withpernyataan diperkenalkan, atau dalam Python 2.6, tetapi didukung dalam Python 2.7 dan Python 3.1 atau lebih baru.

http://docs.python.org/reference/compound_stmts.html#the-with-statement http://docs.python.org/release/3.1/reference/compound_stmts.html#the-with-statement

Jika Anda menulis kode yang harus dijalankan dengan Python 2.5, 2.6 atau 3.0, buat withpernyataan seperti yang disarankan atau digunakan jawaban lain contextlib.nested.

steveha
sumber
28

Gunakan blok bersarang seperti ini,

with open(newfile, 'w') as outfile:
    with open(oldfile, 'r', encoding='utf-8') as infile:
        # your logic goes right here
RanRag
sumber
12

Anda dapat membuat sarang dengan balok. Seperti ini:

with open(newfile, 'w') as outfile:
    with open(oldfile, 'r', encoding='utf-8') as infile:
        for line in infile:
            if line.startswith(txt):
                line = line[0:len(txt)] + ' - Truly a great person!\n'
            outfile.write(line)

Ini lebih baik daripada versi Anda karena Anda menjamin outfileakan ditutup meskipun kode Anda mengalami pengecualian. Jelas Anda bisa melakukannya dengan mencoba / akhirnya, tetapi withmerupakan cara yang tepat untuk melakukan ini.

Atau, seperti yang baru saja saya pelajari, Anda dapat memiliki beberapa manajer konteks dalam pernyataan with seperti yang dijelaskan oleh @steveha . Bagi saya itu merupakan opsi yang lebih baik daripada bersarang.

Dan untuk pertanyaan kecil terakhir Anda, pengembalian tidak memiliki tujuan nyata. Saya akan menghapusnya.

David Heffernan
sumber
Terima kasih banyak. Saya akan mencobanya dan menerima jawaban Anda jika / ketika saya membuatnya bekerja.
Disnami
Terima kasih lagi. Harus menunggu tujuh permen sebelum aku bisa menerimanya.
Disnami
7
@Disnami pastikan Anda menerima jawaban yang benar (dan bukan yang ini!) ;-)
David Heffernan
1

Terkadang, Anda mungkin ingin membuka jumlah file yang bervariasi dan memperlakukan masing-masing dengan cara yang sama, Anda bisa melakukannya dengan ini contextlib

from contextlib import ExitStack
filenames = [file1.txt, file2.txt, file3.txt]

with open('outfile.txt', 'a') as outfile:
    with ExitStack() as stack:
        file_pointers = [stack.enter_context(open(file, 'r')) for file in filenames]                
            for fp in file_pointers:
                outfile.write(fp.read())                   
saudara laki-laki
sumber