2016-03-24 37 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()類型在C中被稱爲PyUnicode,上面的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

難道你不需要帶有'u'參數的'PyArg_ParseTuple'嗎?但它的確依賴於方法表中的參數類型(如METH_VARARGS),您還沒有顯示。 – cdarke

+0

是的,事實上,PyArg_parseTupel可以完美解決這個問題。但是在「python cookbook3」中說過,沒有使用PyArg_ParseTuple就有另一種鍛鍊。 – sun

+0

我並沒有想到代碼的任何其他部分可能會出錯,因爲它適用於其他功能。我在問題描述中添加了整個代碼。 – sun

回答

3

如果目標是完全接受一個參數,則函數should be declared as METH_O而不是METH_VARARGS;前者傳遞單個參數而沒有包裝,後者包裝在tuple中,需要解壓或解析才能獲得PyUnicode*

+0

謝謝,你正確的點。 – sun

相關問題