Возбуждение событий Python

vozbuzhdenie sobytij python Интеграция Python/C

Для моделирования действительных событий можно вызвать через созданный модуль C функцию Python Trigger_Event, которая сгенерирует событие.

Иными словами, в этом примере используются оба знакомых нам интерфейса — расширения и встраивания — для регистрации и вызова программного кода обработчика события на Python. Чтобы лучше узнать, как действует этот прием, внимательно изучите его реализацию в примере 20.30.

Пример 20.30. PP4E\Integrate\Embed\Regist\cregister.c

#include <Python.h> #include <stdlib.h> /***********************************************/

/* 1) передача событий объекту Python */

/* вместо этого можно было бы выполнять строки */ /***********************************************/

static PyObject *Handler = NULL; /* содержит объект Python в C */

void Route_Event(char *label, int count) {

char *cres;

PyObject *args, *pres;

/* вызов обработчика Python */

args = Py_BuildValue("(si)", label, count); /* создать список

аргументов */

pres = PyEval_CallObject(Handler, args); /* применение: выполнить вызов */

Py_DECREF(args); /* добавить контроль ошибок */

if (pres != NULL) {

/* использовать результат и уменьшить счетчик ссылок на него */ PyArg_Parse(pres, "s", &cres);

printf("%s\n", cres);

Py_DECREF(pres);

}

}

/*************************************************************/

/* 2) модуль расширения python для регистрации обработчиков */

/* python импортирует этот модуль для установки обработчиков */ /*************************************************************/

static PyObject *

Register_Handler(PyObject *self, PyObject *args) {

/* сохранить вызываемый объект Python */

Py_XDECREF(Handler); /* вызывался прежде? */

PyArg_Parse(args, "(O)", &Handler); /* один аргумент */

Py_XINCREF(Handler); /* добавить ссылку */

Py_INCREF(Py_None); /* вернуть ‘None’: успех */ return Py_None;

}

static PyObject *

Trigger_Event(PyObject *self, PyObject *args) {

/* позволить Python имитировать событие, перехваченное C */ static count = 0;

Route_Event("spam", count++);

Py_INCREF(Py_None); return Py_None;

}

static PyMethodDef cregister_methods[] = {

{"setHandler", Register_Handler, METH_VARARGS, ""}, /* имя, адр.

функ.,…*/ {"triggerEvent", Trigger_Event, METH_VARARGS, ""},

{NULL, NULL, 0, NULL} /* конец таблицы */

};

static struct PyModuleDef cregistermodule = {

PyModuleDef_HEAD_INIT, "cregister", /* имя модуля */ "cregister mod", /* описание модуля, может быть NULL */ -1, /* размер структуры для каждого экземпляра, -1=глоб. перем. */ cregister_methods /* ссылка на таблицу методов */

};

PyMODINIT_FUNC

PyInit_cregister() /* вызывается первой инструкцией импортирования */ {

return PyModule_Create(&cregistermodule);

}

Конечно, эта программа на C является модулем расширения Python, а не самостоятельной программой C со встроенным программным кодом Python (хотя программа на C могла бы быть верхним уровнем). Для компиляции ее в файл динамически загружаемого модуля выполните make-файл, представленный в примере 20.31 в Cygwin (или аналогичный ему make-файл на других платформах). Как мы узнали выше в этой главе, получающийся файл cregister.dll будет загружен при первом импорте в сценарии Python, если поместить его в каталог, находящийся в пути поиска модулей Python (например, . или содержащийся в PYTHONPATH).

Пример 20.31. PP4E\Integrate\Embed\Regist\makefile.regist

######################################################################

#   makeфайл для Cygwin, выполняющий сборку cregister.dll, динамически

#   загружаемого модуля расширения на C (разделяемого), который

#   будет импортироваться сценарием register.py

######################################################################

PYLIB = /usr/local/bin

PYINC = /usr/local/include/python3.1

CMODS = cregister.dll

all: $(CMODS)

cregister.dll: cregister.c

gcc cregister.c -g -I$(PYINC) -shared -L$(PYLIB) -lpython3.1 -o $@

clean:

rm -f *.pyc $(CMODS)

Теперь, когда у нас есть модуль расширения C для регистрации и вызова обработчиков Python, нам нужны лишь какие-нибудь обработчики Python. Модуль Python, представленный в примере 20.32, определяет две функции обработчиков обратного вызова, импортирует модуль расширения C для регистрации обработчиков и генерирует события.

Пример 20.32. PP4E\Integrate\Embed\Regist\register.py

######################################################################### в Python, регистрирует обработчики событий, которые будут вызываться из C; скомпилируйте и скомпонуйте программный код на C и запустите этот сценарий командой python register.py

#########################################################################

#   ############################################

#   эти функции Python будут вызываться из C;

#   обрабатывать события и возвращать результат

#   ############################################

def callback1(label, count):

return ‘callback1 => %s number %i’ % (label, count)

def callback2(label, count):

return ‘callback2 => ‘ + label * count

#   #################################################

#   Python вызывает модуль расширения C

# для регистрации обработчиков, возбуждает события

##################################################

import cregister

print(‘\nTest1:’)

cregister.setHandler(callback1) # зарегистрировать функциюобработчик

for i in range(3):

cregister.triggerEvent() # имитировать события, перехватываемые слоем C

print(‘\nTest2:’)

cregister.setHandler(callback2)

for i in range(3):

cregister.triggerEvent() # передаст события функции callback2

Вот и все — интеграция обработчиков обратного вызова Python/C готова к работе. Чтобы запустить систему, выполните сценарий Python. Он зарегистрирует одну функцию, сгенерирует три события, затем изменит обработчик событий и повторит все снова:

/PP4E/Integrate/Embed/Regist$ make -f makefile.regist

gcc cregister.c -g -I/usr/local/include/python3.1 -shared -L/usr/local/bin -lpython3.1 -o cregister.dll

/PP4E/Integrate/Embed/Regist$ python register.py

Test1:

callback1 => spam number 0

callback1 => spam number 1

callback1 => spam number 2

Test2:

callback2 => spamspamspam

callback2 => spamspamspamspam

callback2 => spamspamspamspamspam

Этот вывод производит функция в программе C маршрутизации событий, но в нем присутствуют значения, возвращаемые функциями обработчиков в модуле Python. В действительности здесь незаметно много чего происходит. Когда Python возбуждает событие, между двумя языками происходит такая передача управления:

1.      Из Python в функцию маршрутизации событий C.

2.     Из функции маршрутизации событий C в функцию-обработчик Python.

3.     Обратно в функцию маршрутизации событий C (которая выводит полученные результаты).

4.      Наконец, обратно в сценарий Python.

Таким образом, мы переходим из Python в C, оттуда в Python и еще раз обратно. Попутно управление передается через интерфейсы расширения и встраивания. Во время работы обработчика обратного вызова Python активными оказываются два уровня Python и один уровень C посередине. К счастью, это действует — API Python отличается реентерабельностью, поэтому не нужно беспокоиться по поводу того, что одновременно активны несколько уровней интерпретатора Python. Каждый уровень выполняет свой программный код и действует независимо.

Попробуйте по результатам работы и исходному программному коду этого примера проследить порядок выполнения операций, чтобы лучше понять, как он действует. А теперь перейдем к последнему короткому примеру, пока у нас еще есть время и место для исследований, — для симметрии попробуем использовать классы Python из программного кода на C.

Использованная литература:

Марк Лутц — Программирование на Python, 4-е издание, II том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий