Объединение функций C и Python в модуле
Вопрос
У меня есть модуль расширения C, в который я хотел бы добавить некоторые служебные функции Python. Есть ли рекомендуемый способ сделать это?
Например:
import my_module
my_module.super_fast_written_in_C()
my_module.written_in_Python__easy_to_maintain()
Меня в первую очередь интересует Python 2.x.
Решение
Обычный способ сделать это: mymod.py содержит служебные функции, написанные на Python, и импортирует вкусности в модуль _mymod, который написан на C и импортирован из _mymod.so или _mymod.pyd. Например, посмотрите на ... / Lib / csv.py в вашем дистрибутиве Python.
Другие советы
Префикс вашего собственного расширения с подчеркиванием. Затем в Python создайте модуль-обертку, который импортирует это собственное расширение и добавляет некоторые другие не собственные подпрограммы поверх этого.
Существующие ответы описывают наиболее часто используемый метод: он имеет потенциальное преимущество, заключающееся в том, что он допускает реализацию чисто Python (или других языков) на платформах, на которых недоступно скомпилированное расширение C (включая Jython и IronPython). р>
В некоторых случаях, однако, может не стоить разбивать модуль на слой C и слой Python только для того, чтобы предоставить несколько дополнительных функций, которые более разумно написаны на Python, чем на C. Например, gmpy (строки 7113 и далее в настоящее время), по порядку чтобы включить выборку экземпляров типа gmpy
, используется:
copy_reg_module = PyImport_ImportModule("copy_reg");
if (copy_reg_module) {
char* enable_pickle =
"def mpz_reducer(an_mpz): return (gmpy.mpz, (an_mpz.binary(), 256))\n"
"def mpq_reducer(an_mpq): return (gmpy.mpq, (an_mpq.binary(), 256))\n"
"def mpf_reducer(an_mpf): return (gmpy.mpf, (an_mpf.binary(), 0, 256))\n"
"copy_reg.pickle(type(gmpy.mpz(0)), mpz_reducer)\n"
"copy_reg.pickle(type(gmpy.mpq(0)), mpq_reducer)\n"
"copy_reg.pickle(type(gmpy.mpf(0)), mpf_reducer)\n"
;
PyObject* namespace = PyDict_New();
PyObject* result = NULL;
if (options.debug)
fprintf(stderr, "gmpy_module imported copy_reg OK\n");
PyDict_SetItemString(namespace, "copy_reg", copy_reg_module);
PyDict_SetItemString(namespace, "gmpy", gmpy_module);
PyDict_SetItemString(namespace, "type", (PyObject*)&PyType_Type);
result = PyRun_String(enable_pickle, Py_file_input,
namespace, namespace);
Если вы хотите, чтобы эти несколько дополнительных функций " оставались рядом " в вашем модуле (не обязательно в этом примере) вы, конечно, будете использовать объект вашего модуля, созданный Py_InitModule3
(или любым другим методом) и его PyModule_GetDict
, а не временный словарь как пространство имен для PyRun_String
. И, конечно, есть более сложные подходы, чем для PyRun_String
требуемых операторов def
и class
, но для достаточно простых случаев этот простой подход на самом деле может быть достаточно.