В примерах, приводившихся до сего момента, программный код на языке C выполнялся и вызывал программный код Python из обычной последовательности команд основной программы. Однако программы не всегда работают таким образом. В некоторых случаях они создаются на основе архитектуры управ ле ния со бы тия ми, когда программный код выполняется только в ответ на те или иные события. Событием может являться щелчок конечным пользователем на кнопке в графическом интерфейсе, получение сигнала, переданного операционной системой, или просто выполнение программой действий, ассоциируемых с вводом данных в таблицу.
Так или иначе, программный код в такой архитектуре обычно организуется в виде обработчиков обратных вызовов — фрагментов программного кода, выполнение которых организовано логикой, обрабатывающей события. Для реализации обработчиков обратного вызова в такой системе довольно легко можно использовать встроенный программный код Python. В действительности для запуска обработчиков на языке Python слой обработки событий может просто использовать инструменты API вызова встроенного кода, с которыми мы познакомились в этой главе.
Единственный новый прием в этой модели состоит в том, чтобы сообщить слою C о том, какой программный код должен выполняться для каждого события. Обработчики каким-то образом должны быть зарегистрированы в C для связи с возможными событиями. В целом существует большое разнообразие способов добиться такой связи между программным кодом и событиями. Например, программы на языке C могут: • Загружать и вызывать функ ции по имени события из одного или нескольких файлов мо дулей.
• Загружать и выполнять стро ки программного кода, ассоциированные с именами событий, из базы дан ных.
• Загружать и выполнять программный код, ассоциируемый с те га- ми событий в HTML или XML.
• Выполнять программный код Python, который обращается к C с запросом о том, что должно быть выполнено.
И так далее. В действительности механизмом регистрации обратного вызова может стать все, что каким-то образом ассоциирует объекты или строки с идентификаторами. У некоторых из таких приемов есть свои преимущества. Например, получение программного кода обратного вызова из файлов модулей поддерживает динамическую повторную загрузку (imp.reload действует в отношении модулей, но не обновляет объекты, хранящиеся непосредственно). При этом ни в одной из первых трех схем не требуется писать специальные программы Python, занимающиеся только регистрацией обработчиков для последующего выполнения.
Однако чаще, по-видимому, для регистрации обработчиков обратного вызова используется последний подход: регистрация обработчиков в C программным кодом Python при обратном вызове C через интерфейс расширений. Хотя в этой схеме есть свои минусы, она предоставляет естественную и прямую модель в ситуациях, где обратные вызовы ассоциируются с большим числом объектов.
Рассмотрим, например, графический интерфейс, построенный в виде дерева объектов виджетов в сценарии Python. Если с каждым объектом дерева может быть связан обработчик события, проще будет регистрировать обработчики при вызове методов виджетов, образующих дерево. При связывании обработчиков с объектами виджетов в отдельной структуре, такой как файл модуля или файл XML, потребуется дополнительная работа с перекрестными ссылками, чтобы поддерживать соответствие обработчиков дереву.
Фактически, если вам требуется более практичный пример обработчиков событий на Python, загляните в реализацию библиотеки tkinter, которую мы широко использовали в этой книге. В библиотеке tkinter используются обе технологии, расширения и встраивания. Интерфейс рас шире ния в ней используется для регистрации обработчиков обратного вызова на Python, которые позднее запускаются в ответ на события в графическом интерфейсе, с применением интерфейса встраи ва- ния. Вы можете исследовать реализацию библиотеки tkinter, которая включена в пакет с исходными текстами Python, — логика взаимодействия с библиотекой Tk в ней довольно сложна для восприятия, но используемая в ней модель является достаточно прямолинейной.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011