【问题标题】:write() versus writelines() and concatenated stringswrite() 与 writelines() 和连接字符串
【发布时间】:2012-09-04 20:12:00
【问题描述】:

所以我正在学习 Python。我正在学习课程并遇到了一个问题,我必须将大量 target.write() 压缩成一个 write(),同时在每个用户输入变量(write() 的对象)之间有一个 "\n"

我想出了:

nl = "\n"
lines = line1, nl, line2, nl, line3, nl
textdoc.writelines(lines)

如果我尝试这样做:

textdoc.write(lines)

我得到一个错误。但如果我输入:

textdoc.write(line1 + "\n" + line2 + ....)

然后它工作正常。为什么我不能在write() 中使用字符串作为换行符,但我可以在writelines() 中使用它?

Python 2.7

【问题讨论】:

  • lines 在您的示例中不是字符串。它是一个由六个字符串组成的元组。

标签: python string file-io python-2.x


【解决方案1】:
  • writelines 需要一个可迭代的字符串
  • write 需要一个字符串。

line1 + "\n" + line2 将这些字符串合并为一个字符串,然后将其传递给write

请注意,如果您有很多行,您可能需要使用"\n".join(list_of_lines)

【讨论】:

  • 更具体地说,writelines 需要一个可迭代的。您可以使用列表、元组或生成器。
  • 谢谢您的回答先生。我假设我应该创建一个字符串列表,然后将其传递给 .join(list) ?
  • 如果有很多行,为什么要使用write 而不是writelines? Writelines 的性能可能会更好,因为它不必创建临时连接字符串,只需遍历行。
  • @hBy2Py:正好相反:stackoverflow.com/a/6165711/281545
  • 单个字符串在 Python 中也是一个可迭代对象
【解决方案2】:

为什么我不能在 write() 中使用字符串作为换行符,但我可以在 writelines() 中使用它?

想法如下:如果您想编写单个字符串,您可以使用write() 来执行此操作。如果您有一系列字符串,您可以使用writelines() 将它们全部写入。

write(arg) 需要一个字符串作为参数并将其写入文件。如果您提供字符串列表,它将引发异常(顺便向我们显示错误!)。

writelines(arg) 需要一个可迭代对象作为参数(可迭代对象可以是元组、列表、字符串或最一般意义上的迭代器)。迭代器中包含的每个项目都应该是一个字符串。您提供了一个字符串元组,所以一切正常。

字符串的性质对这两个函数都无关紧要,即它们只是将您提供的任何内容写入文件。有趣的部分是writelines() 自己不添加换行符,所以方法名称实际上可能相当混乱。它实际上的行为类似于一个名为write_all_of_these_strings(sequence) 的虚构方法。

以下是 Python 中一种将字符串列表写入文件的惯用方式,同时将每个字符串保留在自己的行中:

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.write('\n'.join(lines))

这会为您关闭文件。构造'\n'.join(lines) 连接(连接)列表lines 中的字符串,并使用字符'\n' 作为胶水。它比使用+ 运算符更有效。

从相同的lines序列开始,以相同的输出结束,但使用writelines()

lines = ['line1', 'line2']
with open('filename.txt', 'w') as f:
    f.writelines("%s\n" % l for l in lines)

这利用了生成器表达式并动态创建以换行符结尾的字符串。 writelines() 遍历这个字符串序列并写入每一项。

编辑:您应该注意的另一点:

write()readlines() 在引入 writelines() 之前就已经存在。 writelines() 是后来作为readlines() 的对应物引入的,这样就可以轻松写入刚刚通过readlines() 读取的文件内容:

outfile.writelines(infile.readlines())

真的,这就是writelines 有如此令人困惑的名字的主要原因。而且,今天,我们真的不想再使用这种方法了。 readlines()writelines() 开始写入数据之前将整个文件读取到您机器的内存中。首先,这可能会浪费时间。为什么不在读取其他部分的同时开始写入部分数据?但是,最重要的是,这种方法可能非常消耗内存。在输入文件大于机器内存的极端情况下,这种方法甚至行不通。这个问题的解决方案是只使用迭代器。一个工作示例:

with open('inputfile') as infile:
    with open('outputfile') as outfile:
        for line in infile:
            outfile.write(line)

这会逐行读取输入文件。只要读取一行,就会将此行写入输出文件。从示意图上讲,内存中总是只有一行(相比之下,在 readlines/writelines 方法的情况下整个文件内容都在内存中)。

【讨论】:

  • @AbeLinkon:我不支持这个结论。 write()writelines() 基本上是等价的,它们的用法也是个人品味的问题。然而,重要的是要注意,对于一个非常长的字符串列表(称为lines),编写f.write('\n'.join(lines)) 的效率低于for l in line: f.write('%s\n' % l)。在第一种情况下,在写入之前在内存中创建了一个全新的非常长的字符串。在第二种情况下,数据是分段写入的。
  • f.write('\n'.join(lines)) 运行时没有添加最后一个 nl。
  • 当然你不会做outf.writelines(inf.readlines()),而是outf.writelines(inf)。我们不想再使用的函数是readlines() 而不是writelines()
  • @moooeeeep:虽然writelines() 的功能/实现没有任何问题,但正如解释的那样,它的语义不太理想。这就是为什么我从来没有使用过它。我从来没有错过它。
  • @AbeLinkon - 也许你应该考虑接受这个答案,它显然比你最初接受的要好
【解决方案3】:

实际上,我认为问题在于您的变量“行”不好。您将行定义为元组,但我相信 write() 需要一个字符串。您只需将逗号更改为加号 (+)。

nl = "\n"
lines = line1+nl+line2+nl+line3+nl
textdoc.writelines(lines)

应该可以。

【讨论】:

    【解决方案4】:

    如果您只想保存和加载列表,请尝试Pickle

    泡菜保存:

    with open("yourFile","wb")as file:
     pickle.dump(YourList,file)
    

    和加载:

    with open("yourFile","rb")as file:
     YourList=pickle.load(file)
    

    【讨论】:

      【解决方案5】:

      Zed Shaw 书中的习题 16?您可以按如下方式使用转义字符:

      paragraph1 = "%s \n %s \n %s \n" % (line1, line2, line3)
      target.write(paragraph1)
      target.close()
      

      【讨论】:

      • 非常弱的解决方案。如果你想以这种方式连接多行,你应该这样做:" \n ".join((line1, line2, line3)).
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-13
      • 2023-04-06
      • 2012-02-24
      • 2011-11-09
      • 1970-01-01
      相关资源
      最近更新 更多