使用Python扩展C程序无法使用swig将字典解析为C函数

时间:2014-10-07 22:16:54

标签: python swig

我无法使用swing模块将字典从python解析为C程序。我编写了一个wrapper_dict.c和struct.c程序。

wrapper.c 
    #include <Python.h>
    #include "struct.h"
    PyObject *dictionary(PyObject *self, PyObject *args) {
            PyObject *dict;
            int result;
            if (!PyArg_ParseTuple(args, "O", &dict))
                     return NULL;
            result = printBook(&dict);
            return Py_BuildValue("i", result);
    }
    static PyMethodDef dictMethods[] = {
             { "printBook", dictionary, 1 },
             { NULL, NULL }
    };
    void initdict() {
            PyObject *m;
            m = Py_InitModule("dict", dictMethods);
    }
Struct.c: 
    #include<stdio.h>
    #include<string.h>
    #include "struct.h"
    int printBook (struct Books *book) {
            printf(" Book title: %s\n", book->title);
            printf(" Book author: %s\n", book->author);
            printf(" Book subject: %s\n", book->subject);
            printf(" Book book_id: %d\n", book->book_id);
            return 1;
    }

使用动态加载:

   xyz@M:~/Python/Cprogam/work$ gcc -fpic -c $(pkg-config --cflags --libs python2) wrapper_dict.c struct.c
    xyz@M:~/Python/Cprogam/work$ gcc -shared wrapper_dict.o struct.o -o dictmod.so

当我将字典传递给printBook时,我看到printf语句返回一堆垃圾值。

 xyz@M:~/Python/Cprogam/work$ python
    Python 2.7.6 (default, Mar 22 2014, 22:59:38)
    [GCC 4.8.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import dict
    >>> books= { 'title':'C progamming', 'author' : 'J k', 'subject' : 'telecomm', 'book_id': '345524'}
    >>>
   >>> dict.printBook(books)
   Book title: t?"?/0l?
   Book author: s?D
   Book subject:
   Book book_id: 4
   1

我错过了什么吗?请告诉我。提前致谢。

1 个答案:

答案 0 :(得分:1)

您必须将Python对象转换为正确的C结构。

这是一个有效的例子。错误检查是为了简洁而遗漏,我猜到了struct.h。我还使用Python 3.3 x64并使用Python的调试版本构建来检查引用计数:

wrapper.c

#include <Python.h>
#include "struct.h"
PyObject *wrap_printBook(PyObject *self, PyObject *args)
{
        PyObject *dict,*py_subject,*py_title,*py_author,*py_book_id;
        struct Books book;
        int result;

        // Parse the Python function arguments.  Expect one object.
        if (!PyArg_ParseTuple(args, "O", &dict))
            return NULL;
        // Expect a Python dictionary, retrieve the expected string values.
        // Note PyDict_GetItemString returns a borrowed reference.  Don't DECREF it.
        py_subject = PyDict_GetItemString(dict,"subject");
        py_title = PyDict_GetItemString(dict,"title");
        py_author = PyDict_GetItemString(dict,"author");
        py_book_id = PyDict_GetItemString(dict,"book_id");
        // Copy the strings into the C structure.
        // Unsafe copy, I know.  I'm not doing all the work :)
        strcpy(book.subject,PyUnicode_AsUTF8(py_subject));
        strcpy(book.author,PyUnicode_AsUTF8(py_author));
        strcpy(book.title,PyUnicode_AsUTF8(py_title));
        // I made book_id an int, so convert the PyUnicode string to a PyInt, then an int.
        py_book_id = PyLong_FromUnicodeObject(py_book_id,10); // convert to PyLong (new ref!)
        book.book_id = PyLong_AsLong(py_book_id);
        Py_DECREF(py_book_id); // release ref
        // Now that the PyDict has been converted to a C value, call the function.
        result = printBook(&book);
        return Py_BuildValue("i", result);
}
static PyMethodDef bookMethods[] = {
    {"printBook",  wrap_printBook, METH_VARARGS, "Call printBook."},
    {NULL, NULL, 0, NULL}
};
static struct PyModuleDef bookModule = {
   PyModuleDef_HEAD_INIT, "book", NULL, -1, bookMethods
};
PyMODINIT_FUNC PyInit_book(void) {
    return PyModule_Create(&bookModule);
}

struct.h

#define MAX_STRING 80
struct Books
{
    char title[MAX_STRING];
    char author[MAX_STRING];
    char subject[MAX_STRING];
    int book_id;
};

int printBook (struct Books *book);

输出:

Python 3.3.2 (VS110.diff:bca965c8a064+, Jun  1 2013, 13:52:13) [MSC v.1700 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import book
[64847 refs]
>>> book.printBook({'subject':'subject1','title':'title1','author':'author1','book_id':'123456'})
 Book title: title1
 Book author: author1
 Book subject: subject1
 Book book_id: 123456
1
[64852 refs]
>>> book.printBook({'subject':'subject1','title':'title1','author':'author1','book_id':'123456'})
 Book title: title1
 Book author: author1
 Book subject: subject1
 Book book_id: 123456
1
[64852 refs] # multiple calls, no reference leaks!