我想将包含Unicode值的嵌套列表转换为latin-1编码的csv(以便我可以在Web响应中传输结果并让最终用户的本地Excel打开文件)。
我们正在过渡到Py3,因此最好同时对Py2和Py3使用相同的代码(出于维护和覆盖的原因)。
我们的适用于py2的Python 2代码:
from cStringIO import StringIO
def rows_to_csv_data(rows):
rows = [[col.encode('latin-1') for col in row] for row in rows]
buf = StringIO()
writer = csv.writer(buf)
writer.writerows(rows)
return buf.getvalue()
一个简单的测试用例:
def test_rows_to_csv_data():
rows = [
[u'helloæ', u'worldø']
]
binary_data = rows_to_csv_data(rows)
assert binary_data == u"helloæ,worldø\r\n".encode('latin-1')
# Update: the data is never written to a file, but sent with a web response:
response = http.HttpResponse(content_type='text/csv')
response['Content-Disposition'] = 'attachment; filename=hello.csv'
response.write(binary_data)
assert response.serialize() == b'Content-Type: text/csv\r\nContent-Disposition: attachment; filename=hello.csv\r\n\r\nhello\xe6,world\xf8\r\n'
我找不到使用将来的或六个库来实现此目的的便捷方法。
使用from io import StringIO
给我(Py3):
Expected :b'hello\xe6,world\xf8\r\n'
Actual :b'hello\\xe6',b'world\\xf8'\r\n
和Py2:
> writer.writerows(rows)
E TypeError: unicode argument expected, got 'str'
使用from io import BytesIO as StringIO
可用于Py2,但Py3可以:
rows = [[b'hello\xe6', b'world\xf8']]
def rows_to_csv_data(rows):
rows = [[col.encode('latin-1') for col in row] for row in rows]
buf = StringIO()
writer = csv.writer(buf)
> writer.writerows(rows)
E TypeError: a bytes-like object is required, not 'str'
这是我在这种情况下不了解的错误消息...
是否可以编写一个适用于两个Python的函数,还是我需要一个完全独立的Py3函数?
答案 0 :(得分:2)
以下是通过测试的Python 2和3之间差异的说明。在Python 2.7和Python 3.6上进行了测试。
#!coding:utf8
import io
import csv
import sys
def rows_to_csv_data(rows):
if sys.version_info.major == 2:
rows = [[col.encode('latin1') for col in row] for row in rows]
buf = io.BytesIO()
else:
buf = io.StringIO(newline='')
writer = csv.writer(buf)
writer.writerows(rows)
if sys.version_info.major == 2:
return buf.getvalue()
else:
return buf.getvalue().encode('latin1')
def test_rows_to_csv_data():
rows = [[u'helloæ', u'worldø']]
binary_data = rows_to_csv_data(rows)
assert binary_data == u"helloæ,worldø\r\n".encode('latin-1')
test_rows_to_csv_data()