【问题标题】:How to open a file using the open with statement如何使用 open with 语句打开文件
【发布时间】:2012-03-06 04:19:00
【问题描述】:

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

【问题讨论】:

  • “意味着我需要将名称存储在一个临时位置”?你能解释一下你的意思吗?
  • 请注意,filter()a built-in function,因此您可能应该为您的函数选择一个不同的名称。
  • @Tom 命名空间中的函数是否覆盖了内置函数?
  • @UpTide:是的,Python 以 LEGB 顺序运行——本地、封闭、全局、内置(参见 stackoverflow.com/questions/291978/…)。所以,如果你做一个全局函数(filter()),它会在内置的filter()之前被发现

标签: python file python-3.x file-io io


【解决方案1】:

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 来指定要返回的值。)

在引入with 语句时,Python 2.5 或 Python 2.6 不支持将多个 open() 项与 with 一起使用,但在 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

【讨论】:

    【解决方案2】:

    像这样使用嵌套块,

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

    【讨论】:

      【解决方案3】:

      你可以嵌套你的 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 是这样做的正确方法。

      或者,正如我刚刚了解到的,您可以在 described by @steveha 的 with 语句中拥有多个上下文管理器。在我看来,这似乎是比嵌套更好的选择。

      对于您的最后一个小问题,返回没有真正的目的。我会删除它。

      【讨论】:

        【解决方案4】:

        有时,您可能希望打开不同数量的文件并以相同的方式对待每个文件,您可以使用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())                   
        

        【讨论】:

          猜你喜欢
          • 2014-03-07
          • 2011-06-04
          • 1970-01-01
          • 2020-03-16
          • 1970-01-01
          • 2018-04-14
          • 1970-01-01
          • 2018-10-29
          相关资源
          最近更新 更多