“单个”\n 在第三个字段中作为数据字符出现。因此,该字段被引用,以便 csv 阅读器将其视为数据的一部分。它不是“行终止符”(应称为行分隔符)或其一部分。为了更好地理解引用,请删除quoting=csv.QUOTE_NONNUMERIC。
\r\n 的产生是因为 csv 以 dialect.lineterminator 终止行,dialect.lineterminator 的默认值为 \r\n。换句话说,“通用换行符”设置被忽略了。
更新
就 newline 参数而言,io.StringIO 的 2.7 和 3.2 文档几乎相同。
换行参数的工作方式与 TextIOWrapper 类似。默认是
不做换行翻译。
我们将检查下面的第一句话。第二句话对于输出是正确的,取决于你对“默认”和“换行翻译”的解释。
TextIOWrapper 文档:
换行符可以是 None、''、'\n'、'\r' 或 '\r\n'。它控制着
处理行尾。如果它是无,通用换行符是
启用。启用此功能后,输入时,行结尾为 '\n'、'\r' 或
'\r\n' 在返回给调用者之前被转换为 '\n'。
相反,在输出时,'\n' 被转换为系统默认行
分隔符,os.linesep。如果换行符是它的任何其他合法值,
读取文件时,该换行符成为换行符,并且它是
未翻译返回。输出时,'\n' 被转换为换行符。
Windows 上的 Python 3.2:
>>> from io import StringIO as S
>>> import os
>>> print(repr(os.linesep))
'\r\n'
>>> ss = [S()] + [S(newline=nl) for nl in (None, '', '\n', '\r', '\r\n')]
>>> for x, s in enumerate(ss):
... m = s.write('foo\nbar\rzot\r\n')
... v = s.getvalue()
... print(x, m, len(v), repr(v))
...
0 13 13 'foo\nbar\rzot\r\n'
1 13 12 'foo\nbar\nzot\n'
2 13 13 'foo\nbar\rzot\r\n'
3 13 13 'foo\nbar\rzot\r\n'
4 13 13 'foo\rbar\rzot\r\r'
5 13 15 'foo\r\nbar\rzot\r\r\n'
>>>
第 0 行显示没有newline arg 的“默认”不涉及\n(或任何其他字符)的翻译。 肯定不会将'\n' 转换为os.linesep
第 1 行显示您使用 newline=None 得到的(应该与第 0 行相同,不是吗??)实际上是 INPUT 通用换行符翻译——奇怪!
第 2 行:newline='' 没有变化,就像第 0 行一样。它肯定不会将 '\n' 转换为 ''。
第 3、4 和 5 行:正如文档所说,'\n' 被转换为 newline arg 的值。
等效的 Python 2.X 代码产生与 Python 2.7.2 相同的结果。
更新 2 为了与内置 open() 保持一致,默认值应为 os.linesep,如文档所述。要获得 no-translation-on-output 行为,请使用 newline=''。注意:open() 文档更加清晰。我明天会提交错误报告。