在Windows中编写一个Python .CSV文件,可以同时适用于Python 2.7+和Python 3.3+。

16

编辑:我已将此放入标题中,但刚意识到我在正文中没有提及。这似乎是特定于Windows的。

我在编写一个脚本,使用csv Python模块输出内容时遇到了困难,因为该脚本需要同时支持Python 2.7和3.3。

第一次尝试在Python 2.7中按预期工作:

with open('test.csv', 'wb') as csv_file:
    writer = csv.DictWriter(csv_file, ['header1', 'header2'])
    writer.writeheader()
    for item in items:
        writer.writerow(item)

然而,当在Python 3.3中运行相同的东西时,你最终会得到:

TypeError: 'str' does not support the buffer interface

所以我将'wb'更改为'wt',程序可以运行,但现在文件中每隔一行会有一个额外的空行。

为了解决这个问题,我进行了以下更改:

with open('test.csv', 'wt') as csv_file:
with open('test.csv', 'wt', newline='') as csv_file:

但现在它无法运行在Python 2.7上:

TypeError: 'newline' is an invalid keyword argument for this function

我知道我可以做这样的事情:

try:
    with open('test.csv', 'wt', newline='') as csv_file:
        writer = csv.DictWriter(csv_file, ['header1', 'header2'])
        writer.writeheader()
        for item in items:
            writer.writerow(item)
except TypeError:
    with open('test.csv', 'wb') as csv_file:
        writer = csv.DictWriter(csv_file, ['header1', 'header2'])
        writer.writeheader()
        for item in items:
            writer.writerow(item)

然而,这有一些严重的重复。

是否有更清晰的方法来做到这一点?

编辑:测试数据很简单,没有换行符或其他任何东西:

items = [{'header1': 'value', 'header2': 'value2'},
         {'header1': 'blah1', 'header2': 'blah2'}]

你不能只使用'w'代替'wb''wt'吗? - nathancahill
当您在Python 2中运行脚本时,您items列表中的字符串是unicode字符串吗?这些值始终为ASCII码,还是可能包含需要进行编码的其他字符?即使您能够在两个Python版本下运行相同的代码,您也可能得不到相同的结果! - Blckknght
@Blckknght - 我已经将测试数据添加到问题底部。它只是ASCII文本。 - Tamerz
2个回答

8

我尝试过几种方法。在我看来,简单地使用'w'可能是一个解决方案:

with open('test.csv', 'w') as csv_file:
    writer = csv.DictWriter(csv_file, fieldnames=['header1', 'header2'], lineterminator='\n')
    # write something

1
如果我这样做,仍然会在每隔一行出现空白行。你是在Windows上还是其他平台上尝试过这个? - Tamerz
@Tamerz,你的数据中有额外的换行符,所以你得到了额外的新行... .strip() 可能是你需要的。 - gboffi
@Tamerz 我用了一些假数据,结果很好。所以我认为你的数据也有问题。 - ljk321
wwt相同。 - cdarke
@skyline75489 - 已将测试数据添加到原始问题中。您可以看到它只是一个包含几个字符串的字典。 - Tamerz
显示剩余6条评论

8
这里有一个更简单的通用方法:
import sys

if sys.version_info[0] == 2:  # Not named on 2.6
    access = 'wb'
    kwargs = {}
else:
    access = 'wt'
    kwargs = {'newline':''}

with open('test.csv', access, **kwargs) as csv_file:
    writer = csv.DictWriter(csv_file, ['header1', 'header2'])
    writer.writeheader()
    for item in items:
        writer.writerow(item)

这里的原则不是试图去对抗Python 2和3之间的差异,而是使用条件代码。在编写代码时,如果没有这种测试,你只能走得那么远,迟早你将不得不测试Python的版本。


我认为让 **kwargs 参与可能是一个好的解决方案。虽然它仍然不太美观,但比我之前的所有重复代码都要好得多。在我的情况下,这绝对可行。谢谢。 - Tamerz
我选择了@skyline75489给出的答案,但我仍然喜欢这个作为将来的参考。有时候我需要做到这一点,但不知道最好的方法。 - Tamerz
1
@Tamerz:看看[我的答案](http://stackoverflow.com/a/41913382/355230),适用于Python的两个版本,可以处理文件的读取和写入(同时,默认情况下像`open()`一样,如果没有明确指定,则默认为读取模式)。它还不需要使用全局变量。 - martineau

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接