Создание модуля расширения для Python на языке Си

Простой, а главное — рабочий пример модуля расширения на языке C для питона. Модуль называется example, а реализовывает одну функцию hello, которая вызывается с параметром who и возвращает «Hello %s» % who.

Листинг модуля example.c

Python 2.xx

#include <Python.h>
 
PyObject *hello( PyObject *self, PyObject *args, PyObject *kwargs )
{
    char *who = 0;
    static char *keywords[] = {"who", NULL};
    PyObject *result = 0;
 
    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", keywords, &who))
    {
        return NULL;
    }
 
    result = PyString_FromString("Hello ");
    PyString_Concat(&result, PyString_FromString(who));
    return result;
}
 
 
static PyMethodDef example_methods[] = 
{
    { "hello", (PyCFunction) hello, METH_KEYWORDS, "hello(who) -- return \"Hello who\"" },
    { NULL, 0, 0, NULL }
};
 
 
PyMODINIT_FUNC initexample()
{
    (void) Py_InitModule("example", example_methods);
 
    if (PyErr_Occurred())
    {
        PyErr_SetString(PyExc_ImportError, "example module init failed");
    }
}

Python 3.xx

#include <Python.h>
 
PyObject *hello( PyObject *self, PyObject *args, PyObject *kwargs )
{
    char *who = 0;
    static char *keywords[] = {"who", NULL};
 
    if (PyArg_ParseTupleAndKeywords(args, kwargs, "s", keywords, &who))
    {
        return PyUnicode_FromFormat("Hello %s", who);
    }
    return NULL;
}
 
 
static PyMethodDef example_methods[] = 
{
    { "hello", (PyCFunction) hello, METH_KEYWORDS, "hello(who) -- return \"Hello who\"" },
    { NULL, 0, 0, NULL }
};
 
 
static struct PyModuleDef example_module = 
{
    PyModuleDef_HEAD_INIT,
    "example",
    NULL,
    -1,
    example_methods
};
 
 
PyMODINIT_FUNC PyInit_example(void)
{
    return PyModule_Create(&example_module);
}

Листинг setup.py

setup.py

from distutils.core import setup
from distutils.extension import Extension
examplemodule = Extension(name="example", sources=['example.c', ])
setup(name="example", ext_modules=[examplemodule])

Компилируем:

python setup.py build

Инсталлируем:

python setup.py install

Выполняем простенький тест:

from example import hello
print hello(who="world!")

Радуемся :)

Hello world!

Полезные ссылки (на английском):

Цикл статей про Boost.Python на хабре:

P.S. По своему опыту могу сказать, что Boost.Python — редкостное барахло, возьмите лучше библиотеку PyCXX.

10 комментариев
  1. написал(а) Дмитрий (8 октября 2012, 09:27)

    Спасибо!
    Я бы еще добавил перед «Выполняем простенький тест» раздел «Инсталлируем» с одной строчкой —

    [sudo] python setup.py install

    И еще интересно как можно собранный у меня на машине пакет инсталлировать на компьютер клиента?

    т.е. прокатит ли в скрипте инсталляции моей программы прописать строчку

    python setup.py install

    чтобы потом использовать данный пакет в своей программе?

    1. написал(а) eJ (8 октября 2012, 11:20)

      Спасибо за дополнение. Обновил запись.

      По поводу инсталляции — никогда не возникало такой необходимости, но вот эта команда должна создавать инсталляционный пакет (можно выбрать tgz, zip, rpm и инсталлятор для win32):

      python setup.py bdist

      Вот здесь можно найти подробности: http://docs.python.org/distutils/builtdist.html

      А вот здесь можно узнать, как работать с получившимся пакетом: http://docs.python.org/install/index.html

  2. написал(а) z (9 июля 2014, 00:04)

    Проверил, работает. Вместо всяког хабраклала.

    1. написал(а) eJ (9 июля 2014, 10:46)

      Рекомендую библиотеку PyCXX для Python функций из C++ и наоборот.

    2. написал(а) Hound (6 ноября 2014, 22:41)

      >> import example
      Traceback (most recent call last):
      File «», line 1, in

      а у меня чего-то с такой ошибкой вываливается…

      1. написал(а) eJ (7 ноября 2014, 00:01)

        Сложно сказать по такой ошибке что происходит. Вы пишете это в файле или в интерпретаторе?

      2. написал(а) eJ (7 ноября 2014, 00:08)

        Нашел ваш пост тут: http://python.su/forum/topic/25437/

        У меня на FreeBSD все нормально завелось, возможно проблема на вашей стороне.

  3. написал(а) Николай (22 августа 2015, 11:39)

    В первом листинге опечатка нужно PyMODINIT_FUNC вместо PYMODINIT_FUNC

    1. написал(а) eJ (22 августа 2015, 12:13)

      Спасибо! Исправил.

  4. написал(а) Вячеслав (14 декабря 2019, 11:37)

    Норм. Спасибо!
    Я совместно юзаю cython. Пишу на питоне Модуль, после перегоняю его в СИ «cython -3 —no-docstrings *.pyx», а дальше все как в Вашей статье. Получаю *.pyd а дальше pyinstaller в дело. Вот такие пироги =)))
    Остался вопрос для успокоения души… Так ли просто теперь хакнуть мой *.pyd и добраться до исходников питона?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Блог Евгения Жирнова