справочник по Python. мм isbn 9785932861578 9 785932 861578
Скачать 4.21 Mb.
|
Потоки управления Глобальная блокировка интерпретатора не позволяет интерпретатору вы- полнять более одного потока управления одновременно. Если функция, реализованная в модуле расширения, выполняется достаточно продолжи- тельное время, она может заблокировать выполнение остальных потоков управления. Это обусловлено тем, что перед каждым вызовом функции в расширении приобретается блокировка. Если модуль расширения допу- скает возможность работы в многопоточном режиме, в нем можно восполь- зоваться следующими макроопределениями, позволяющими освобождать и повторно приобретать глобальную блокировку интерпретатора: Py_BEGIN_ALLOW_THREADS Освобождает глобальную блокировку интерпретатора и позволяет интер- претатору выполнять другие потоки управления одновременно с расшире- нием. Расширение на языке C не должно вызывать функции Python C API после освобождения блокировки. 754 Глава 26. Расширение и встраивание интерпретатора Python Py_END_ALLOW_THREADS Повторно приобретает глобальную блокировку интерпретатора. Расшире- ние будет приостановлено, пока блокировка не будет приобретена. Следующий пример иллюстрирует использование этих макроопределений: PyObject *py_wrapper(PyObject *self, PyObject *args) { ... PyArg_ParseTuple(args, ...) Py_BEGIN_ALLOW_THREADS result = run_long_calculation(args); Py_END_ALLOW_THREADS ... return Py_BuildValue(fmt,result); } Встраивание интерпретатора Python Интерпретатор Python также может встраиваться в приложения на язы- Python также может встраиваться в приложения на язы- также может встраиваться в приложения на язы- ке C. При встраивании интерпретатор Python действует, как библиотека, с помощью которой программы на языке C могут инициализировать ин- C могут инициализировать ин- могут инициализировать ин- терпретатор, запускать с его помощью сценарии и фрагменты программно- го кода, загружать библиотечные модули, а также манипулировать функ- циями и объектами, реализованными на языке Python. Порядок встраивания При встраивании за запуск интерпретатора отвечает программа на язы- ке C. Ниже приводится пример простой программы на языке C, которая иллюстрирует минимально возможный программный код, реализующий встраивание: #include int main(int argc, char **argv) { Py_Initialize(); PyRun_SimpleString(“print(‘Hello World’)”); Py_Finalize(); return 0; } В этом примере программа инициализирует интерпретатор, выполняет ко- роткий сценарий в виде строки и закрывает интерпретатор. Прежде чем углубляться в эту тему далее, обычно бывает полезно рассмотреть действу- ющий пример. Компиляция и связывание Чтобы скомпилировать программу на языке C, которая встраивает интер- C, которая встраивает интер- , которая встраивает интер- претатор, в системе UNIX, программа должна подключить заголовочный файл “Python.h” и быть скомпонована с библиотекой интерпретатора, такой как libpython2.6.a. Заголовочный файл обычно находится в каталоге /usr/ local/include/python2.6 , а библиотека – в каталоге /usr/local/lib/python2.6/ Встраивание интерпретатора Python 755 config . В системе Windows эти файлы находятся в каталоге установки Py- Windows эти файлы находятся в каталоге установки Py- эти файлы находятся в каталоге установки Py- Py- thon. Имейте в виду, что интерпретатор может зависеть от других библио- . Имейте в виду, что интерпретатор может зависеть от других библио- тек, которые вам также следует включить в инструкции компоновки. К со- жалению, эта процедура зависит от типа платформы и от того, с какими па- раметрами была выполнена сборка интерпретатора Python, поэтому вам, возможно, придется повозиться. Запуск и основные операции интерпретатора Ниже перечислены функции, которые используются для запуска интер- претатора и выполнения сценариев с его помощью: int PyRun_AnyFile(FILE *fp, char *filename) Если fp представляет интерактивное устройство, например терминал в UNIX, эта функция вызовет функцию PyRun_InteractiveLoop(). В против- В против- против- против- ном случае – функцию PyRun_SimpleFile(). В аргументе filename передается строка с именем входного потока. Это имя будет фигурировать в сообще- с именем входного потока. Это имя будет фигурировать в сообще- с именем входного потока. Это имя будет фигурировать в сообще- именем входного потока. Это имя будет фигурировать в сообще- именем входного потока. Это имя будет фигурировать в сообще- входного потока. Это имя будет фигурировать в сообще- входного потока. Это имя будет фигурировать в сообще- потока. Это имя будет фигурировать в сообще- потока. Это имя будет фигурировать в сообще- . Это имя будет фигурировать в сообще- Это имя будет фигурировать в сообще- имя будет фигурировать в сообще- имя будет фигурировать в сообще- будет фигурировать в сообще- будет фигурировать в сообще- фигурировать в сообще- фигурировать в сообще- в сообще- в сообще- сообще- сообще- ниях интерпретатора об ошибках. Если в аргументе filename передать NULL, в качестве имени файла по умолчанию будет использоваться строка “???”. int PyRun_SimpleFile(FILE *fp, char *filename) Похожа на функцию PyRun_SimpleString(), за исключением того, что про- грамма на языке Python извлекается из файла fp. int PyRun_SimpleString(char *command) Выполняет команду command в контексте модуля __main__ интерпретатора. Возвращает 0 в случае успеха и -1 – в случае появления исключения. int PyRun_InteractiveOne(FILE *fp, char *filename) Выполняет единственную интерактивную команду. int PyRun_InterativeLoop(FILE *fp, char *filename) Запускает интерпретатор в интерактивном режиме. void Py_Initialize() Инициализирует интерпретатор Python. Эта функция должна вызываться перед любыми другими функциями C API интерпретатора, за исключени- любыми другими функциями C API интерпретатора, за исключени- любыми другими функциями C API интерпретатора, за исключени- другими функциями C API интерпретатора, за исключени- другими функциями C API интерпретатора, за исключени- функциями C API интерпретатора, за исключени- функциями C API интерпретатора, за исключени- C API интерпретатора, за исключени- интерпретатора, за исключени- , за исключени- за исключени- исключени- исключени- ем функций Py_SetProgramName(), PyEval_InitThreads(), PyEval_ReleaseLock() и PyEval_AcquireLock(). int Py_IsInitialized() Возвращает 1, если интерпретатор был инициализирован, 0 – в противном случае. void Py_Finalize() Завершает работу интерпретатора, уничтожая все вложенные потоки управления и объекты, созданные после вызова Py_Initialize(). Обычно эта функция освобождает всю память, выделенную интерпретатором. Однако циклические ссылки и модули расширений способны вызвать утечки па- мяти, которые не могут быть устранены этой функцией. 756 Глава 26. Расширение и встраивание интерпретатора Python void Py_SetProgramName(char *name) Определяет имя программы, которое обычно можно найти в переменной argv[0] модуля sys. Эта функция должна вызываться только перед вызовом Py_Initialize() char *Py_GetPrefix() Возвращает путь установки платформонезависимых файлов. Это то же са- мое значение, которое можно найти в переменной sys.prefix. char *Py_GetExecPrefix() Возвращает путь установки платформозависимых файлов. Это то же самое значение, которое можно найти в переменной sys.exec_prefix. char *Py_GetProgramFullPath() Возвращает полный путь к выполняемому файлу интерпретатора Python. char *Py_GetPath() Возвращает путь по умолчанию поиска модулей. Возвращаемая строка со- держит имена каталогов, разделенные символом-разделителем, который используется текущей платформой (: – в UNIX, ; – в DOS/Windows). int PySys_SetArgv(int argc, char **argv) Определяет параметры командной строки для заполнения значения пере- менной sys.argv. Эта функция должна вызываться до вызова функции Py_ Initialize() Обращение к интерпретатору Python из программы на языке C Несмотря на существование большого количества способов доступа к ин- терпретатору из программ на языке C, тем не менее чаще всего используют- C, тем не менее чаще всего используют- , тем не менее чаще всего используют- ся четыре основные операции: • Импортирование библиотечных модулей Python (имитация инструк- Python (имитация инструк- (имитация инструк- ции import). • Получение ссылок на объекты, определяемые в модулях. • Вызов функций на языке Python, обращение к классам и методам. • Обращение к атрибутам объектов (к данным или к методам) Все эти операции могут выполняться с помощью следующих функций ин- терфейса C API доступа к программному коду Python: PyObject *PyImport_ImportModule(const char *modname) Импортирует модуль modname и возвращает ссылку на объект модуля. PyObject *PyObject_GetAttrString(PyObject *obj, const char *name) Возвращает значение атрибута объекта. Эквивалентно обращению к атри- буту obj.name в программе на языке Python. Встраивание интерпретатора Python 757 int PyObject_SetAttrString(PyObject *obj, const char *name, PyObject *value) У станавливает значение атрибута объекта. Эквивалентно операции при- сваивания obj.name = value в программе на языке Python. PyObject *PyEval_CallObject(PyObject *func, PyObject *args) Вызывает функцию func с аргументами args. func – это вызываемый объект на языке Python (функция, метод, класс и так далее). args – кортеж аргу- ментов. PyObject *PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyOb- ject *kwargs) Вызывает функцию func с позиционными аргументами args и именован- ными аргументами kwargs. func – это вызываемый объект, args – кортеж и kwargs – словарь. Следующий пример иллюстрирует использование этих функций для об- ращения к различным компонентам модуля re из программы на языке C. Эта программа выводит все cтроки, прочитанные из потока stdin и соответ- ствующие регулярному выражению, переданному пользователем в виде аргумента. #include “Python.h” int main(int argc, char **argv) { PyObject *re; PyObject *re_compile; PyObject *pat; PyObject *pat_search; PyObject *args; char buffer[256]; ёёё if (argc != 2) { fprintf(stderr,”Порядок использования: %s шаблон\n”,argv[0]); exit(1); } ёёё Py_Initialize(); ёёё /* import re */ re = PyImport_ImportModule(“re”); ёёё /* pat = re.compile(pat,flags) */ re_compile = PyObject_GetAttrString(re,”compile”); args = Py_BuildValue(“(s)”, argv[1]); pat = PyEval_CallObject(re_compile, args); Py_DECREF(args); ёёё /* pat_search = pat.search – связанный метод */ pat_search = PyObject_GetAttrString(pat,”search”); ёёё /* Прочитать строки и выполнить сопоставление */ while (fgets(buffer,255,stdin)) { PyObject *match; args = Py_BuildValue(“(s)”, buffer); ёёё 758 Глава 26. Расширение и встраивание интерпретатора Python /* match = pat.search(buffer) */ match = PyEval_CallObject(pat_search,args); Py_DECREF(args); if (match != Py_None) { printf(“%s”,buffer); } Py_XDECREF(match); } Py_DECREF(pat); Py_DECREF(re_compile); Py_DECREF(re); Py_Finalize(); return 0; } При встраивании интерпретатора Python чрезвычайно важно обеспечить корректное управление счетчиками ссылок. В частности, необходимо уменьшать счетчики ссылок в любых объектах, созданных в программном коде на языке C или возвращаемых программному коду на языке C в ре- C или возвращаемых программному коду на языке C в ре- или возвращаемых программному коду на языке C в ре- C в ре- в ре- зультате вызовов функций. Преобразование объектов на языке Python в объекты на языке C Важной проблемой при использовании встроенного интерпретатора явля- ется преобразование результатов вызова функций или методов на языке Python в соответствующее представление на языке C. Как правило, при выполнении таких операций необходимо заранее точно знать тип данных, возвращаемых функцией. К сожалению, не существует высокоуровневой вспомогательной функции, такой как PyArg_ParseTuple(), для преобразова- ния единственного объекта. Однако существует несколько низкоуровне- вых функций, которые перечислены ниже, способных преобразовывать некоторые простейшие типы данных Python в соответствующее представ- Python в соответствующее представ- в соответствующее представ- ление на языке C, при условии, что заранее точно известно, преобразование какого объекта на языке Python выполняется: Функции преобразования объектов Python в представление на языке C long PyInt_AsLong(PyObject *) long PyLong_AsLong(PyObject *) double PyFloat_AsDouble(PyObject *) char *PyString_AsString(PyObject *) (только в Python 2) char *PyBytes_AsString(PyObject *) (только в Python 3) Если вам потребуется работать с более сложными типами данных, обра- щайтесь к описанию C API (http://docs.python.org/c-api). Модуль ctypes 759 Модуль ctypes М одуль ctypes обеспечивает доступ к функциям в библиотеках DLL и в раз- DLL и в раз- и в раз- деляемых библиотеках, написанных на языке C, из программного кода на языке Python. Хотя вам и потребуется знать определенные детали, относя- Python. Хотя вам и потребуется знать определенные детали, относя- . Хотя вам и потребуется знать определенные детали, относя- щиеся к библиотеке (имена, входные аргументы, типы аргументов и воз- вращаемых значений и так далее), вы можете использовать модуль ctypes для доступа к программному коду, написанному на языке C, без необходи- C, без необходи- , без необходи- мости создавать функции-обертки и даже без необходимости использовать компилятор C. Модуль ctypes является важным модулем в стандартной библиотеке, обладающим весьма широкими функциональными возмож- ностями. Ниже описываются значимые составляющие этого модуля, зна- комство с которыми необходимо, чтобы начать работать с ним. Загрузка разделяемых библиотек Ниже перечислены классы, которые используются для загрузки разделяе- мых библиотек, написанных на языке C, и возвращают экземпляры, пред- C, и возвращают экземпляры, пред- , и возвращают экземпляры, пред- ставляющие их содержимое: CDLL(name [, mode [, handle [, use_errno [, use_last_error]]]]) Класс, представляющий стандартную разделяемую библиотеку языка C. В аргументе name передается имя библиотеки, такое как ‘libc.so.6’ или ‘ms- vcrt.dll’ . В аргументе mode передается флаг, который определяет, как будет загружаться библиотека и как она будет передаваться функции dlopen() в UNIX. Этот аргумент представляет собой битовую маску, составленную из флагов RTLD_LOCAL, RTLD_GLOBAL и RTLD_DEFAULT (по умолчанию), объединяе- мых битовой операцией ИЛИ. В Windows аргумент mode игнорируется. Ар- игнорируется. Ар- . Ар- Ар- гумент handle определяет дескриптор уже загруженной библиотеки (если доступен). По умолчанию он принимает значение None. В аргументе use_er- _er- er- rno передается логический флаг, добавляющий дополнительный уровень безопасности при работе с переменной errno языка C в загружаемой библио- C в загружаемой библио- в загружаемой библио- теке. Когда задействован этот уровень, локальная копия переменной errno в текущем потоке управления сохраняется перед вызовом любых внешних функций и восстанавливается после вызова. По умолчанию аргумент use_ errno принимает значение False. В аргументе use_last_error передается ло- гический флаг, который разрешает использовать пару функций get_last_ error() и set_last_error() для управления системным кодом ошибки. Чаще всего эти функции используются в Windows. По умолчанию аргумент use_ last_error принимает значение False. WinDLL(name [, mode [, handle [, use_errno [, use_last_error]]]]) То же, что и CDLL(), за исключением того, что в данном случае предпола- гается, что все функции в загружаемой библиотеке следуют стандартному соглашению Windows stdcall о вызовах (Windows). Следующую функцию можно использовать, чтобы искать в системе раз- деляемые библиотеки и сконструировать имя, подходящее для использо- вания в аргументе name предыдущих конструкторов классов. Эта функция определена в модуле ctypes.util: 760 Глава 26. Расширение и встраивание интерпретатора Python find_library(name) Определена в модуле ctypes.util. Возвращает полный путь к библиотеке с именем name. В аргументе name передается имя библиотеки без расшире- ния, такое как ‘libc’, ‘libm’ и так далее. Строка, возвращаемая функцией, содержит полный путь к файлу библиотеки, такой как ‘/usr/lib/libc.so.6’. Поведение этой функции в значительной степени зависит от типа плат- формы, от системных настроек размещения разделяемых библиотек и от окружения (например, от значения переменной окружения LD_LIBRARY_PATH и других параметров). Возвращает None, если библиотеку не удалось оты- скать. Внешние функции Экземпляры разделяемых библиотек, созданные вызовом конструктора CDLL() , действуют как прокси-объекты, обеспечивающие доступ к содер- жимому библиотеки языка C. Чтобы обратиться к элементу библиотеки, достаточно просто использовать оператор доступа к атрибутам. Например: >>> |