Cách mở tệp bằng cách mở bằng câu lệnh


200

Tôi đang xem cách thực hiện nhập và xuất tệp trong Python. Tôi đã viết đoạn mã sau để đọc danh sách tên (mỗi dòng trên một tệp) vào một tệp khác trong khi kiểm tra tên với tên trong tệp và thêm văn bản vào các lần xuất hiện trong tệp. Các mã hoạt động. Nó có thể được thực hiện tốt hơn?

Tôi muốn sử dụng with open(...câu lệnh cho cả tệp đầu vào và đầu ra nhưng không thể thấy chúng có thể nằm trong cùng một khối nghĩa là tôi cần lưu trữ tên ở một vị trí tạm thời.

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

"có nghĩa là tôi cần lưu trữ tên ở một vị trí tạm thời"? Bạn có thể giải thích những gì bạn có ý nghĩa bởi điều này?
S.Lott

4
Lưu ý rằng đó filter()một hàm tích hợp và vì vậy có lẽ bạn nên chọn một tên khác cho hàm của mình.
Tom

2
@Tom có ​​một hàm trong không gian tên ghi đè hàm tích hợp không?
UpTide

2
@UpTide: Có, Python hoạt động theo thứ tự LEGB - Địa phương, Bao vây, Toàn cầu, Tích hợp (xem stackoverflow.com/questions/291978/ Lỗi ). Vì vậy, nếu bạn tạo một hàm toàn cầu ( filter()), nó sẽ được tìm thấy trước khi tích hợp sẵnfilter()
Tom

Câu trả lời:


308

Python cho phép đặt nhiều open()câu lệnh trong một with. Bạn phân tách dấu phẩy chúng. Mã của bạn sau đó sẽ là:

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

Và không, bạn không đạt được bất cứ điều gì bằng cách đặt một rõ ràng returnvào cuối chức năng của bạn. Bạn có thể sử dụng returnđể thoát sớm, nhưng bạn đã có nó ở cuối và chức năng sẽ thoát mà không có nó. (Tất nhiên với các hàm trả về giá trị, bạn sử dụng returnđể chỉ định giá trị cần trả về.)

Sử dụng nhiều open()mục với withkhông được hỗ trợ trong Python 2.5 khi withcâu lệnh được giới thiệu hoặc trong Python 2.6, nhưng nó được hỗ trợ trong Python 2.7 và Python 3.1 trở lên.

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

Nếu bạn đang viết mã phải chạy trong Python 2.5, 2.6 hoặc 3.0, hãy lồng các withcâu lệnh như các câu trả lời khác được đề xuất hoặc sử dụng contextlib.nested.


28

Sử dụng các khối lồng nhau như thế này,

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

12

Bạn có thể lồng bạn với các khối. Như thế này:

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)

Điều này tốt hơn phiên bản của bạn bởi vì bạn đảm bảo rằng nó outfilesẽ bị đóng ngay cả khi mã của bạn gặp ngoại lệ. Rõ ràng bạn có thể làm điều đó với thử / cuối cùng, nhưng withlà cách đúng đắn để làm điều này.

Hoặc, như tôi vừa tìm hiểu, bạn có thể có nhiều trình quản lý bối cảnh trong một câu lệnh với mô tả của @steveha . Đó dường như là một lựa chọn tốt hơn so với làm tổ.

Và đối với câu hỏi nhỏ cuối cùng của bạn, lợi nhuận không phục vụ mục đích thực sự. Tôi sẽ loại bỏ nó.


Cảm ơn rất nhiều. Tôi sẽ thử nó và chấp nhận câu trả lời của bạn nếu / khi tôi làm cho nó hoạt động.
Disnami

Cảm ơn một lần nữa. Phải đợi bảy phút trước khi tôi có thể chấp nhận.
Disnami

7
@Disnami đảm bảo bạn chấp nhận câu trả lời đúng (và đây không phải câu trả lời này!) ;-)
David Heffernan

1

Đôi khi, bạn có thể muốn mở một số lượng tệp khác nhau và xử lý từng tệp giống nhau, bạn có thể làm điều này với 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())                   
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.