Python 3兼容性问题

时间:2015-03-10 09:40:14

标签: python c python-c-extension

问题描述

我必须将一些代码迁移到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:iterable必须返回像对象一样的字节

2 个答案:

答案 0 :(得分:3)

一种选择是以二进制模式打开文件:

open("file.txt", "rb")

那应该创建一个返回字节序列的迭代器。

Python 3字符串被假定为Unicode,没有正确的编码/解码,它们不应被解释为字节序列。如果您正在读取纯ASCII文本而不是二进制数据流,则还可以从Unicode转换为ASCII。请参阅PyUnicode_AsASCIIString()及相关功能。

答案 1 :(得分:0)

如@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]

P.S。您的C扩展代码中也有错误:Parser_read有3个参数,其中2个名为unused_x。只有用METH_KEYWORDS注释的方法才有3个参数(PyCFunctionWithKeywords);所有其他人,包括METH_NOARGS必须是带有2个参数的函数(PyCFunction)。