2016-03-24 3 views
1

Я писал функцию расширения C, которая должна была принять объект str в качестве аргумента. Код показан ниже:python3 str объект не может пройти PyUnicode_Check

static PyObject *py_print_chars(PyObject *self, PyObject *o) { 
PyObject *bytes; 
char *s; 
if (!PyUnicode_Check(o)) { 
    PyErr_SetString(PyExc_TypeError, "Expected string"); 
    return NULL; 
} 
bytes = PyUnicode_AsUTF8String(o); 
s = PyBytes_AsString(bytes); 
print_chars(s); 
Py_DECREF(bytes); 
Py_RETURN_NONE; 
} 

Но, как я протестировать модуль в Python3 консоли, я нахожу str объекты не могут пройти PyUnicode_Check:

>>> from sample2 import *  
>>> print_chars('Hello world')  
Traceback (most recent call last): 
File "<stdin>", line 1, in <module> 
TypeError: Expected string 

Насколько я знаю, Python 3-ые годы str() тип называется PyUnicode в C, а код C, описанный выше, написан в разделе «python cookbook3» Char15.13. Я просто не могу решить проблему. Может кто-нибудь сказать мне, что не так с моим кодом.

Вот что «питон cookbook3» сказал:

Если по какой-то причине, вы непосредственно работаете с PyObject * и не может использовать PyArg_ParseTuple(), следующие примеры кода показывают, как можно проверить и выписки подходящий char * ссылки, как с байтами и струнного объекта:

/* Some Python Object (obtained somehow) */ 
PyObject *obj; 

/* Conversion from bytes */ 
{ 
    char *s; 
    s = PyBytes_AsString(o); 
    if (!s) { 
     return NULL; /* TypeError already raised */ 
    } 
    print_chars(s); 
} 
/* Conversion to UTF-8 bytes from a string */ 
{ 
    PyObject *bytes; 
    char *s; 
    if (!PyUnicode_Check(obj)) { 
     PyErr_SetString(PyExc_TypeError, "Expected string"); 
     return NULL; 
    } 
    bytes = PyUnicode_AsUTF8String(obj); 
    s = PyBytes_AsString(bytes); 
    print_chars(s); 
    Py_DECREF(bytes); 
} 

и весь код:

#include "Python.h" 
#include "sample.h" 

static PyObject *py_print_chars(PyObject *self, PyObject *o) { 
    PyObject *bytes; 
    char *s; 
    if (!PyUnicode_Check(o)) { 
     PyErr_SetString(PyExc_TypeError, "Expected string"); 
     return NULL; 
    } 
    bytes = PyUnicode_AsUTF8String(o); 
    s = PyBytes_AsString(bytes); 
    print_chars(s); 
    Py_DECREF(bytes); 
    Py_RETURN_NONE; 
} 

/* Module method table */ 
static PyMethodDef SampleMethods[] = { 
    {"print_chars", py_print_chars, METH_VARARGS, "print character"}, 
    { NULL, NULL, 0, NULL} 
}; 

/* Module structure */ 
static struct PyModuleDef samplemodule = { 
PyModuleDef_HEAD_INIT, 
    "sample", 
    "A sample module", 
    -1, 
    SampleMethods 
}; 

/* Module initialization function */ 
PyMODINIT_FUNC 
PyInit_sample2(void) { 
    return PyModule_Create(&samplemodule); 
} 
+0

Вам не нужен 'PyArg_ParseTuple' с аргументом' u' first? Но это зависит от типов аргументов в таблице методов (например, METH_VARARGS), которые вы не указали. – cdarke

+0

Да, factuallty, PyArg_parseTupel может решить эту проблему отлично. Но в «python cookbook3» говорится, что есть еще одна тренировка без использования PyArg_ParseTuple. – sun

+0

Я не думал, что какая-либо часть кода может пойти не так, потому что она хорошо работает для других функций. Я добавляю весь код в описание вопроса. – sun

ответ

3

Если целью является принятие только одного аргумента, функция should be declared as METH_O, а не METH_VARARGS; первый проходит по единственному аргументу без обертывания, последний обертывает tuple, который нужно будет распаковать или проанализировать, чтобы получить внутри PyUnicode*.

+0

Спасибо, вы прямо попали в точку. – sun

Смежные вопросы