如何使用with语句打开文件

265 投票
4 回答
942958 浏览
提问于 2025-04-17 13:02

我正在研究如何在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')

4 个回答

14

你可以把多个“with”块嵌套在一起,像这样:

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 是更合适的做法。

另外,正如我刚刚了解到的,你可以在一个 with 语句中使用多个上下文管理器,正如@steveha所描述的那样。这对我来说似乎比嵌套更好。

至于你最后的小问题,return 实际上没有什么用处。我建议把它去掉。

41

像这样使用嵌套的代码块,

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

在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.
    '''

    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引入with语句的时候,使用多个open()是不被支持的,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

撰写回答