如何使用open with语句打开文件


198

我正在研究如何在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命名空间中的函数是否会覆盖内置函数?
UpTide

2
@UpTide:是的,Python按照LEGB顺序运行-本地,封闭,全局,内置(请参见stackoverflow.com/questions/291978/…)。因此,如果您创建一个全局函数(filter()),它将在内置函数之前找到filter()
Tom

Answers:


306

Python允许将多个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来指定要返回的值。)

引入该语句时,Python 2.5 或Python 2.6 不支持open()与一起使用多个项目,但Python 2.7和Python 3.1或更高版本with支持使用多个项目with

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


28

这样使用嵌套块

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即使您的代码遇到异常,您也可以保证将其关闭。显然,您可以通过try / finally进行操作,但这with是正确的方法。

或者,正如我刚学到的,您可以在@steveha描述的with语句中包含多个上下文管理器。在我看来,这比嵌套是更好的选择。

对于您的最后一个小问题,退货没有实际目的。我会删除它。


非常感谢。如果可以的话,我会尝试一下并接受您的回答。
Disnami 2012年

再次感谢。我必须等七个薄荷糖才能接受。
Disnami

7
@Disnami确保您接受正确的答案(不是这个答案!);-)
David Heffernan 2012年

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())                   
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.