Python3 兼容性问题
Python 3 compatibility issue
问题描述
我必须将一些代码迁移到Python 3. 编译成功终止。但是我在运行时遇到问题:
static PyObject* Parser_read(PyObject * const self, PyObject * unused0, PyObject * unused1) {
//Retrieve bytes from the underlying data stream.
//In this case, an iterator
PyObject * const i = PyIter_Next(self->readIterator);
//If the iterator returns NULL, then no more data is available.
if(i == NULL)
{
Py_RETURN_NONE;
}
//Treat the returned object as just bytes
PyObject * const bytes = PyObject_Bytes(i);
Py_DECREF(i);
if( not bytes )
{
//fprintf(stderr, "try to read %s\n", PyObject_Str(bytes));
PyErr_SetString(PyExc_ValueError, "iterable must return bytes like objects");
return NULL;
}
....
}
在我的 python 代码中,我有类似的东西:
for data in Parser(open("file.txt")):
...
代码在 Python 2 上运行良好。但是在 Python 3 上,我得到:
ValueError: iterable must return bytes like objects
更新
@casevh 的解决方案适用于所有测试用例,除了一个:当我包装流时:
def wrapper(stream):
for data in stream:
for i in data:
yield i
for data in Parser(wrapper(open("file.txt", "rb"))):
...
我得到了:
ValueError:可迭代对象必须 return 字节,如对象
一个选项是以二进制模式打开文件:
open("file.txt", "rb")
那应该创建一个 returns 字节序列的迭代器。
Python 3 个字符串被假定为 Unicode,如果没有适当的 encoding/decoding,它们不应被解释为字节序列。如果您正在阅读纯 ASCII 文本,而不是二进制数据流,您还可以从 Unicode 转换为 ASCII。请参阅 PyUnicode_AsASCIIString()
和相关函数。
如@casevh 所述,在 Python 中,您需要确定数据是二进制 还是 文本。你在迭代行的事实让我认为是后者。
def wrapper(stream):
for data in stream:
for i in data:
yield i
适用于 Python 2,因为迭代 str
将产生 1 个字符的字符串;在 Python 3 中,遍历 bytes
对象将 产生单个字节,它们是 0 - 255 范围内的整数。您可以通过一次使用范围和切片 1 byte/character 使代码在 Python 2 和 3 中以相同的方式工作(并且与上面代码的 Python 2 行为相同):
def wrapper(stream):
for data in stream:
for i in range(len(data)):
yield data[i:i + 1]
P.S。您的 C 扩展代码中也有一个错误:Parser_read
有 3 个参数,其中 2 个名为 unused_x
。只有用 METH_KEYWORDS
注释的方法需要 3 个参数 (PyCFunctionWithKeywords
);所有其他的,包括 METH_NOARGS
必须是接受 2 个参数的函数 (PyCFunction
).
问题描述
我必须将一些代码迁移到Python 3. 编译成功终止。但是我在运行时遇到问题:
static PyObject* Parser_read(PyObject * const self, PyObject * unused0, PyObject * unused1) {
//Retrieve bytes from the underlying data stream.
//In this case, an iterator
PyObject * const i = PyIter_Next(self->readIterator);
//If the iterator returns NULL, then no more data is available.
if(i == NULL)
{
Py_RETURN_NONE;
}
//Treat the returned object as just bytes
PyObject * const bytes = PyObject_Bytes(i);
Py_DECREF(i);
if( not bytes )
{
//fprintf(stderr, "try to read %s\n", PyObject_Str(bytes));
PyErr_SetString(PyExc_ValueError, "iterable must return bytes like objects");
return NULL;
}
....
}
在我的 python 代码中,我有类似的东西:
for data in Parser(open("file.txt")):
...
代码在 Python 2 上运行良好。但是在 Python 3 上,我得到:
ValueError: iterable must return bytes like objects
更新
@casevh 的解决方案适用于所有测试用例,除了一个:当我包装流时:
def wrapper(stream):
for data in stream:
for i in data:
yield i
for data in Parser(wrapper(open("file.txt", "rb"))):
...
我得到了: ValueError:可迭代对象必须 return 字节,如对象
一个选项是以二进制模式打开文件:
open("file.txt", "rb")
那应该创建一个 returns 字节序列的迭代器。
Python 3 个字符串被假定为 Unicode,如果没有适当的 encoding/decoding,它们不应被解释为字节序列。如果您正在阅读纯 ASCII 文本,而不是二进制数据流,您还可以从 Unicode 转换为 ASCII。请参阅 PyUnicode_AsASCIIString()
和相关函数。
如@casevh 所述,在 Python 中,您需要确定数据是二进制 还是 文本。你在迭代行的事实让我认为是后者。
def wrapper(stream):
for data in stream:
for i in data:
yield i
适用于 Python 2,因为迭代 str
将产生 1 个字符的字符串;在 Python 3 中,遍历 bytes
对象将 产生单个字节,它们是 0 - 255 范围内的整数。您可以通过一次使用范围和切片 1 byte/character 使代码在 Python 2 和 3 中以相同的方式工作(并且与上面代码的 Python 2 行为相同):
def wrapper(stream):
for data in stream:
for i in range(len(data)):
yield data[i:i + 1]
P.S。您的 C 扩展代码中也有一个错误:Parser_read
有 3 个参数,其中 2 个名为 unused_x
。只有用 METH_KEYWORDS
注释的方法需要 3 个参数 (PyCFunctionWithKeywords
);所有其他的,包括 METH_NOARGS
必须是接受 2 个参数的函数 (PyCFunction
).