[英]Python 3 compatibility issue
问题描述
我必须将一些代码迁移到Python3。编译成功终止。 但是我在运行时遇到问题:
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:iterable必须返回类似对象的字节
一种选择是以二进制模式打开文件:
open("file.txt", "rb")
那应该创建一个返回字节序列的迭代器。
假定Python 3字符串是Unicode,并且没有正确的编码/解码,因此不应将它们解释为字节序列。 如果您正在读取纯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个字节/字符,可以使代码在Python 2和3中完全相同(并且与上述代码的Python 2行为相同):
def wrapper(stream):
for data in stream:
for i in range(len(data)):
yield data[i:i + 1]
PS您的C扩展代码中也有一个错误: Parser_read
3个参数,其中2个被命名为unused_x
。 只有带有METH_KEYWORDS
注释的方法带有3个参数( PyCFunctionWithKeywords
); 所有其他函数(包括METH_NOARGS
必须是METH_NOARGS
2个参数的函数( PyCFunction
)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.