วิธีเปิดไฟล์โดยใช้คำสั่ง open with


201

ฉันกำลังดูวิธีการอินพุตและเอาต์พุตไฟล์ใน Python ฉันได้เขียนโค้ดต่อไปนี้เพื่ออ่านรายการชื่อ (หนึ่งรายการต่อบรรทัด) จากไฟล์ไปยังไฟล์อื่นในขณะที่ตรวจสอบชื่อกับชื่อในไฟล์และต่อท้ายข้อความที่เกิดขึ้นในไฟล์ รหัสใช้งานได้ ทำได้ดีกว่านี้ไหม

ฉันต้องการใช้with open(...คำสั่งสำหรับทั้งไฟล์อินพุตและเอาต์พุต แต่ไม่สามารถดูว่าพวกเขาสามารถอยู่ในความหมายบล็อกเดียวกันได้หรือไม่ฉันต้องการเก็บชื่อไว้ในตำแหน่งชั่วคราว

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')

"ความหมายฉันจะต้องเก็บชื่อไว้ในที่ตั้งชั่วคราว"? คุณช่วยอธิบายความหมายของสิ่งนี้ได้อย่างไร
S.Lott

4
โปรดทราบว่าfilter()เป็นฟังก์ชันในตัว ดังนั้นคุณควรเลือกชื่ออื่นสำหรับฟังก์ชั่นของคุณ
Tom

2
@Tom ฟังก์ชันในเนมสเปซจะแทนที่ฟังก์ชันในตัวหรือไม่
อั

2
@UpTide: ใช่ Python ทำงานตามคำสั่งของ LEGB - Local, Enclosing, Global, Built-in (ดูstackoverflow.com/questions/291978/… ) ดังนั้นหากคุณสร้างฟังก์ชั่นระดับโลก ( filter()) มันจะพบได้ก่อนที่จะติดตั้งในตัวfilter()
Tom

คำตอบ:


309

งูหลามช่วยให้การวางหลายงบในครั้งเดียวopen() withคุณคั่นด้วยจุลภาค รหัสของคุณจะเป็น:

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')

และไม่คุณจะไม่ได้รับอะไรเลยโดยใส่คำอธิบายไว้returnท้ายฟังก์ชั่น คุณสามารถใช้returnเพื่อออกก่อน แต่คุณมีมันในตอนท้ายและฟังก์ชั่นจะออกโดยไม่ได้ (แน่นอนว่าด้วยฟังก์ชั่นที่คืนค่าคุณใช้returnเพื่อระบุค่าที่จะส่งคืน)

การใช้หลายopen()รายการด้วยwithไม่ได้รับการสนับสนุนใน Python 2.5 เมื่อมีการใช้withคำสั่งหรือใน Python 2.6 แต่ได้รับการสนับสนุนใน Python 2.7 และ Python 3.1 หรือใหม่กว่า

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

หากคุณกำลังเขียนโค้ดที่ต้องทำงานใน Python 2.5, 2.6 หรือ 3.0 ให้ทำwithคำสั่งตามคำแนะนำหรือการใช้contextlib.nestedอื่น ๆ


29

ใช้บล็อกซ้อนกันเช่นนี้

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

12

คุณสามารถซ้อนบล็อกของคุณได้ แบบนี้:

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)

สิ่งนี้ดีกว่ารุ่นของคุณเพราะคุณรับประกันว่าoutfileจะปิดแม้ว่ารหัสของคุณจะพบกับข้อยกเว้น เห็นได้ชัดว่าคุณสามารถทำได้ด้วยการลอง / ในที่สุด แต่withเป็นวิธีที่เหมาะสมในการทำเช่นนี้

หรือที่ผมได้เรียนรู้เพียงแค่คุณสามารถมีผู้จัดการบริบทหลายในที่มีคำสั่งตามที่อธิบายโดย @steveha ที่ดูเหมือนว่าฉันจะเป็นตัวเลือกที่ดีกว่าการทำรัง

และสำหรับคำถามย่อยสุดท้ายของคุณการส่งคืนไม่ได้มีวัตถุประสงค์ที่แท้จริง ฉันจะลบมัน


ขอบคุณมาก ๆ. ฉันจะลองและยอมรับคำตอบของคุณถ้า / เมื่อฉันได้มันไปทำงาน
Disnami

ขอบคุณอีกครั้ง. ต้องรอเจ็ดมินต์ก่อนที่ฉันจะยอมรับได้
Disnami

7
@Disnami ให้แน่ใจว่าคุณยอมรับคำตอบที่ถูกต้อง (และไม่ใช่อย่างนี้!) ;-)
David Heffernan

1

บางครั้งคุณอาจต้องการเปิดไฟล์ที่มีจำนวนตัวแปรและให้แต่ละไฟล์เหมือนกันคุณสามารถทำได้ด้วย 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())                   
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.