Как ускорить Python с помощью C-расширений. Часть 1
Привет, Хабр! Я – Игорь Алимов, ведущий разработчик группы Python в МТС Digital, работаю над продуктами Smart Rollout и B2B-портал. В этой статье я расскажу о том, как писать быстрый код на Python с использованием C-расширений и победить GIL.
На мысли об ускорении Python меня натолкнула статья о языках программирования будущего. Список перспективных (по мнению автора) языков я приводить не буду, но скажу, что языку Python в будущем было отказано. В числе недостатков Python автор выделил низкую производительность и наличие GIL. Действительно, Python не слишком быстрый и имеет блокировку, которая разрешает одновременное выполнение только одного потока инструкций. Что с этим делать? Переучиваться на Java/Go/Rust/____(нужное подчеркнуть/вписать)? Погодите, есть другие способы ускорить Python и нивелировать его недостатки.
Что это за метод?
Пишем первую реализацию на Python. На производительность не обращаем внимания, наша цель – получить результат, чтобы в дальнейшем было, с чем сравнивать. Если на этом этапе производительность нас устраивает – задача выполнена, в противном случае переходим ко второму пункту.
Пытаемся понять, где в коде мы теряем больше всего времени. В простых случаях это понятно сразу, в сложных придется прибегнуть к профилированию кода.
Производим рефакторинг кода так, чтобы выделить в виде отдельной функции, класса или модуля код, на который уходит больше всего времени. На этом этапе производим оптимизацию кода, используя параллельное исполнение и другие приемы, помогающие уменьшить время выполнения. При этом контролируем правильность результата и время. Если результат нас по-прежнему не устраивает – переходим к следующему пункту.
Переписываем проблемный код на C.
Почему именно на C? Для Python существуют порядка десяти различных способов использования нативного кода, но такой метод обеспечит наибольшую производительность при переключении между Python и нативным кодом. Язык C – это interlingua всех языков программирования. Ядро Linux, большинство системных библиотек, GTK и еще много чего написаны на нем.
Даже если библиотека написана на каком-то другом языке программирования, двоичный интерфейс (так называемое ABI) у нее C-подобный. Эталонная реализация Python также написана на C, о чем говорит ее название – CPython. Главный минус – особенности языка C: арифметика указателей, ручное управление памятью, отсутствие средств метапрограммирования. С другой стороны, С – это высокая производительность, прямой доступ к памяти и аппаратуре, стандартный интерфейс. Применение обоих языков программирования позволит использовать их сильные стороны и значительно уменьшит влияние недостатков.
Конкретный пример использования С-расширений
Постановка задачи
Есть некоторая начальная строка, нам необходимо добавить к ней один или несколько случайно выбранных символов из заданного набора, чтобы хеш полной строки имел особый вид. В нашем конкретном случае будем использовать sha256 и хеш полной строки должен начинаться с 8 нулей.
Начальная строка: ‘Начальное значение!’
Набор символов для создания случайной строки: punctuation + digits + ascii_letters из модуля string
Ожидаемое начала хеша: ‘00000000’
Написание первого варианта
Криптофункция хеш по определению является односторонней, поэтому единственный практический способ – это полный перебор всех сочетаний символов из заданного набора, сначала по одному символу, потом по два и так далее. Это позволит пронумеровать все возможные сочетания и написать функцию, которая по номеру возвращает сочетание символов. Первая реализация находится в файле prototype.py. Это простая однопоточная реализация, вот ее особенности:
Использование лога для вывода.
Использование argparse для парсинга аргументов командной строки.
Вводится понятие раунда, по умолчанию 100000000 хешей, по окончании раунда выводится производительность раунда в kH/s (кило хешей в секунду).
Основную работу выполняет функция mining, которая обрабатывает раунд целиком.
Функция get_value по номеру сочетания символов возвращает строку с этими символами.
Для расчета хешей используется библиотечный модуль hashlib.sha256.
Лог работы первого варианта находится в файле prototype.log.
Хеш 00000000331cb4111b0fb7fff9a9014aa45376e25b59516ff57e0789f86d98ce от строки ‘Начальное значение![JBYW’ был получен в 71 раунде, время 3 часа 46 минут 56.715 секунд, средняя производительность 527.490 kH/s
Анализ первого варианта, рефакторинг
И без профилирования понятно, что больше всего времени занимает функция mining. Для ускорения работы используем параллельное вычисление. Помня про GIL, применяем для этого модуль multiprocessing. Каждый раунд делим на несколько параллельно действующих обработчиков (workers), причем новый раунд начинаем, не дожидаясь момента, когда закончат работу все workers предыдущего раунда. Исходный код находится в файле prototype_multi.py. Особенности этой версии:
Добавлена функция form_task, которая формирует задание для очередного раунда.
Функция mining отправляет свой результат в очередь.
В функции main строки 123-133 ставят задание на исполнение.
Строка 134 в функции main ожидает завершения workers.
Строки 135-150 функции main производит анализ возвращаемых результатов.
Результат выполнения второго варианта находится в файле prototype-multi.log. Итоги те же, время выполнения 1 час 1 минута 55.01 секунда, средняя производительность 1933.423 kH/s.
Рекомендации для написания C-функций
Написанное ниже относится к реализации Python на CPython версии 3.9. В других версиях CPython возможны изменения в API. Библиотека собиралась компилятором GCC 11.2.0, сборка и тестирование проводились в Linux. В сборке нативных расширений под Windows есть особенности, которые не отражены в этой статье. Основная документация – Extending and Embedding the Python Interpreter и Python/C API Reference Manual.
Прототип C-функции
Если нужно, чтобы C-функция была видна в Python, она должна иметь следующий прототип:
В первой строке мы определяем макрос PY_SSIZE_T_CLEAN, затем подключаем заголовочный файл Python.h – в нем содержатся прототипы функций, макросы, определения типов данных, которые потребуются при написании кода. Ключевое слово static указывает на область видимости функции, которой является единица компиляции. Проще говоря, функция не видна за пределами текущего файла. Возвращает функция указатель на PyObject, в нем будут возвращены результаты работы функции.
Далее следует имя функции, которое может быть любым. Для упорядочивая имя функции часто состоит из двух частей: имя модуля и имя самой функции, как она будет видна в Python. Хотелось бы заметить, что реальные имена модуля и функции, как они будут видны в Python, задаются в структурах, которые мы обсудим далее. Во избежание путаницы им дают одинаковые имена.
У функции два аргумента, это указатель на модуль, в котором расположена функция, и указатель на аргументы функции. Мы рассматриваем функции с позиционными аргументами. Да, есть возможность задать функцию с ключевыми аргументами, но в этой статье мы о ней говорить не будем. Если функция является методом объекта, то первый указатель будет ссылаться на объект.
Поговорим немного о структуре PyObject. Все сущности (числа, строки, составные типы, объекты, функции, модули) в Python представлены расширениями этой структуры. Правильнее было бы говорить, что они наследуют эту структуру, но в языке C нет наследования. Любые Python-сущности – расширения структуры PyObject и расположены в heap (свободная область памяти между кодом программы и стеком). CPython оперирует указателями на эти объекты – как ссылки, которых в языке C нет. Это порождает особенности работы Python c переменными и данными: мы можем записать в переменную число и строку, но нам не удастся сложить число и строку. А все потому, что переменная имеет тип ссылки на PyObject и в нее можно поместить любое значение. Объекты Python типа int и str не имеют операции +, они обладают различными типами. Эти типы и определяют операции, которые с ними можно проводить, а переменные всегда имеют один и тот же тип – ссылка на PyObject.
Работа с исключениями
При работе C-функции могут возникать невосстановимые ошибки: выделения памяти, открытия файла и прочие. Кажется логичным решением возбудить соответствующее исключение и немедленно прекратить работу функции. Но тут проявляется проблема – в языке C нет исключений.
При написании программ на языке C используется другой подход: каждая функция возвращает признак (обычно это int), если функция выполнилась успешно – возвращается 0, в противном случае – 1. Из этого правила есть исключения, чтобы узнать о них, необходимо изучить документацию на функцию или системный вызов. Также устанавливается специальная переменная errno, локальная для каждого потока выполнения. С ее помощью можно уточнить, что именно пошло не так. В нашем случае мы возвращаем указатель на объект и признаком аварийного завершения будет возврат NULL.
Нужно понимать разницу между Python None и C NULL. Любая функция Python, если мы не возвращаем из нее значения, возвращает None. Это нормальный Python-объект, который имеет адрес, а C-выражение NULL означает отсутствие указателя. Кроме возвращения NULL, наша функция должна установить объект исключения. Делается это следующим образом:
type – указатель на тип исключения.
message – текст сообщения об ошибке.
Есть и общая форма установки исключения:
value — указатель на произвольное значение.
Стоит заметить, что не всегда эти функции вызываются напрямую. Например, при ошибке выделения памяти проще будет сделать:
Функция PyErr_NoMemory сама установит соответствующий объект исключения и вернет NULL, который отдадим вызывающей функции.
Управление памятью
Если не брать в расчет глобальные и локальные переменные потока, в языке C есть два места, где располагаются переменные:
Все переменные, созданные на стеке, автоматически уничтожаются при выходе из функции, при этом их значение теряется. Если в указанном примере опустить вызов free, то при выходе из функции будут утеряно значение buffer, которое является указателем на память в heap и до завершения программы никто не сможет обратиться к этой области. Это явление называется утечкой памяти.
Для программы, которая недолго работает, это не так страшно – при завершении программы вся память будет возвращена операционной системе. Но если у нас утечка памяти в продолжительно работающем сервисе и на каждом запросе к этому сервису мы теряем пару килобайт – через несколько часов память в системе будет полностью израсходована. Тогда к нам в гости придет oom killer и убьет наш процесс. Двойное освобождение памяти даже более критично, чем утечка, оно проводит к немедленному завершению процесса.
Попытка разыменовывать (обратиться к области памяти) неверный указатель также приводит к немедленному завершению процесса (здесь я немного драматизирую ситуацию, так как, возможно, процесс останется жив, но мы точно считаем мусор, который никак не соответствует данным).
Использование ранее освобожденной памяти в языке C носит название неопределенное поведение (undefined behavior, UB). Если повезет – мы считаем данные. Если нет – получим мусор, а попытки записать данные в такую область памяти, скорее всего, приведут к загадочным ошибкам, неправильным результатам, аварийным завершением процесса. Причем ошибки эти проявятся позже, в процессе выполнения программы.
Как в таких, откровенно говоря, спартанских условиях, Python реализует управление памятью? Для этого используются две стратегии: подсчет ссылок и сборщик мусора.
Подсчет ссылок (Reference Counts).
Рассмотрим структуру PyObject, базовую для всех Python-сущностей:
Если не брать в расчет _PyObject_HEAD_EXTRA, то в структуре PyObject всего два поля: ob_type – указатель на тип объекта и ob_refcnt – счетчик ссылок. В поле ob_refcnt указано количество ссылок на объект. Действуют следующие правила при работе со счетчиком ссылок:
Объект никому не принадлежит и находится в общем доступе.
Все, кто заинтересован в использовании этого объекта, должны явно увеличить счетчик ссылок.
После того, как объект становится не нужен, следует уменьшить счетчик ссылок.
Не следует напрямую обращаться к полю ob_refcnt, для этого используются макросы Py_INCREF(x) и Py_DECREF(x).
Если после макроса Py_DECREF(x) счетчик ссылок становится равным 0, объект уничтожается и память освобождается.
Действует правило заимствования – считается, что аргументы функции удерживает вызывающая функция. В возвращаемом результате увеличивает счетчик ссылок создающая его функция и в таком виде его возвращает.
Стратегия с подсчетом ссылок не работает в случае циклических ссылок между объектами. Тогда у обоих (или более) объектов счетчик ссылок никогда не будет равен 0, хотя оба объекта никому не нужны. Для разрешения такой ситуации используется сборщик мусора (garbage collection gc), он находит циклические ссылки и удаляет объекты, входящие в цикл, предварительно проверив, что на них никто больше не ссылается.
Если нашей C-функции потребуется память для собственных нужд, можно использовать стандартные функции malloc/free, но Python/C API Reference Manual/Memory Management рекомендует использовать PyMem_RawMalloc/PyMem_RawCalloc/PyMem_RawRealloc/PyMem_RawFree, которые по своим входным и выходным параметрам соответствуют malloc/calloc/realloc/free. Аргументация такая – сборщику мусора проще выполнять свою работу, если он знает о всей используемой памяти.
На этом я заканчиваю теоретическую часть о написании С-расширений в Python. Во второй части этой статьи продемонстрирую конкретный пример реализации функции mining на C. Подписывайтесь на блог МТС, чтобы не пропустить продолжение.
Если у вас есть вопросы или замечания к первой части – пишите их в комментариях, с радостью ответим на них!
Introduction¶
The Application Programmer’s Interface to Python gives C and C++ programmers access to the Python interpreter at a variety of levels. The API is equally usable from C++, but for brevity it is generally referred to as the Python/C API. There are two fundamentally different reasons for using the Python/C API. The first reason is to write extension modules for specific purposes; these are C modules that extend the Python interpreter. This is probably the most common use. The second reason is to use Python as a component in a larger application; this technique is generally referred to as embedding Python in an application.
Writing an extension module is a relatively well-understood process, where a “cookbook” approach works well. There are several tools that automate the process to some extent. While people have embedded Python in other applications since its early existence, the process of embedding Python is less straightforward than writing an extension.
Many API functions are useful independent of whether you’re embedding or extending Python; moreover, most applications that embed Python will need to provide a custom extension as well, so it’s probably a good idea to become familiar with writing an extension before attempting to embed Python in a real application.
Coding standards¶
If you’re writing C code for inclusion in CPython, you must follow the guidelines and standards defined in PEP 7. These guidelines apply regardless of the version of Python you are contributing to. Following these conventions is not necessary for your own third party extension modules, unless you eventually expect to contribute them to Python.
Include Files¶
All function, type and macro definitions needed to use the Python/C API are included in your code by the following line:
This implies inclusion of the following standard headers: <stdio.h> , <string.h> , <errno.h> , <limits.h> , <assert.h> and <stdlib.h> (if available).
Since Python may define some pre-processor definitions which affect the standard headers on some systems, you must include Python.h before any standard headers are included.
It is recommended to always define PY_SSIZE_T_CLEAN before including Python.h . See Parsing arguments and building values for a description of this macro.
All user visible names defined by Python.h (except those defined by the included standard headers) have one of the prefixes Py or _Py . Names beginning with _Py are for internal use by the Python implementation and should not be used by extension writers. Structure member names do not have a reserved prefix.
User code should never define names that begin with Py or _Py . This confuses the reader, and jeopardizes the portability of the user code to future Python versions, which may define additional names beginning with one of these prefixes.
The header files are typically installed with Python. On Unix, these are located in the directories prefix /include/pythonversion/ and exec_prefix /include/pythonversion/ , where prefix and exec_prefix are defined by the corresponding parameters to Python’s configure script and version is ‘%d.%d’ % sys.version_info[:2] . On Windows, the headers are installed in prefix /include , where prefix is the installation directory specified to the installer.
To include the headers, place both directories (if different) on your compiler’s search path for includes. Do not place the parent directories on the search path and then use #include <pythonX.Y/Python.h> ; this will break on multi-platform builds since the platform independent headers under prefix include the platform specific headers from exec_prefix .
C++ users should note that although the API is defined entirely using C, the header files properly declare the entry points to be extern "C" . As a result, there is no need to do anything special to use the API from C++.
Useful macros¶
Several useful macros are defined in the Python header files. Many are defined closer to where they are useful (e.g. Py_RETURN_NONE ). Others of a more general utility are defined here. This is not necessarily a complete listing.
Use this when you have a code path that cannot be reached by design. For example, in the default: clause in a switch statement for which all possible values are covered in case statements. Use this in places where you might be tempted to put an assert(0) or abort() call.
In release mode, the macro helps the compiler to optimize the code, and avoids a warning about unreachable code. For example, the macro is implemented with __builtin_unreachable() on GCC in release mode.
A use for Py_UNREACHABLE() is following a call a function that never returns but that is not declared _Py_NO_RETURN .
If a code path is very unlikely code but can be reached under exceptional case, this macro must not be used. For example, under low memory condition or if a system call returns a value out of the expected range. In this case, it’s better to report the error to the caller. If the error cannot be reported to caller, Py_FatalError() can be used.
New in version 3.7.
Return the absolute value of x .
New in version 3.3.
Return the minimum value between x and y .
New in version 3.3.
Return the maximum value between x and y .
New in version 3.3.
Convert x to a C string. E.g. Py_STRINGIFY(123) returns "123" .
New in version 3.4.
Return the size of a structure ( type ) member in bytes.
New in version 3.6.
Argument must be a character or an integer in the range [-128, 127] or [0, 255]. This macro returns c cast to an unsigned char .
Like getenv(s) , but returns NULL if -E was passed on the command line (i.e. if Py_IgnoreEnvironmentFlag is set).
Use this for unused arguments in a function definition to silence compiler warnings. Example: int func(int a, int Py_UNUSED(b)) < return a; >.
New in version 3.4.
Use this for deprecated declarations. The macro must be placed before the symbol name.
Changed in version 3.8: MSVC support was added.
Creates a variable with name name that can be used in docstrings. If Python is built without docstrings, the value will be empty.
Use PyDoc_STRVAR for docstrings to support building Python without docstrings, as specified in PEP 7.
Creates a docstring for the given input string or an empty string if docstrings are disabled.
Use PyDoc_STR in specifying docstrings to support building Python without docstrings, as specified in PEP 7.
Objects, Types and Reference Counts¶
Most Python/C API functions have one or more arguments as well as a return value of type PyObject * . This type is a pointer to an opaque data type representing an arbitrary Python object. Since all Python object types are treated the same way by the Python language in most situations (e.g., assignments, scope rules, and argument passing), it is only fitting that they should be represented by a single C type. Almost all Python objects live on the heap: you never declare an automatic or static variable of type PyObject , only pointer variables of type PyObject * can be declared. The sole exception are the type objects; since these must never be deallocated, they are typically static PyTypeObject objects.
All Python objects (even Python integers) have a type and a reference count. An object’s type determines what kind of object it is (e.g., an integer, a list, or a user-defined function; there are many more as explained in The standard type hierarchy ). For each of the well-known types there is a macro to check whether an object is of that type; for instance, PyList_Check(a) is true if (and only if) the object pointed to by a is a Python list.
Reference Counts¶
The reference count is important because today’s computers have a finite (and often severely limited) memory size; it counts how many different places there are that have a reference to an object. Such a place could be another object, or a global (or static) C variable, or a local variable in some C function. When an object’s reference count becomes zero, the object is deallocated. If it contains references to other objects, their reference count is decremented. Those other objects may be deallocated in turn, if this decrement makes their reference count become zero, and so on. (There’s an obvious problem with objects that reference each other here; for now, the solution is “don’t do that.”)
Reference counts are always manipulated explicitly. The normal way is to use the macro Py_INCREF() to increment an object’s reference count by one, and Py_DECREF() to decrement it by one. The Py_DECREF() macro is considerably more complex than the incref one, since it must check whether the reference count becomes zero and then cause the object’s deallocator to be called. The deallocator is a function pointer contained in the object’s type structure. The type-specific deallocator takes care of decrementing the reference counts for other objects contained in the object if this is a compound object type, such as a list, as well as performing any additional finalization that’s needed. There’s no chance that the reference count can overflow; at least as many bits are used to hold the reference count as there are distinct memory locations in virtual memory (assuming sizeof(Py_ssize_t) >= sizeof(void*) ). Thus, the reference count increment is a simple operation.
It is not necessary to increment an object’s reference count for every local variable that contains a pointer to an object. In theory, the object’s reference count goes up by one when the variable is made to point to it and it goes down by one when the variable goes out of scope. However, these two cancel each other out, so at the end the reference count hasn’t changed. The only real reason to use the reference count is to prevent the object from being deallocated as long as our variable is pointing to it. If we know that there is at least one other reference to the object that lives at least as long as our variable, there is no need to increment the reference count temporarily. An important situation where this arises is in objects that are passed as arguments to C functions in an extension module that are called from Python; the call mechanism guarantees to hold a reference to every argument for the duration of the call.
However, a common pitfall is to extract an object from a list and hold on to it for a while without incrementing its reference count. Some other operation might conceivably remove the object from the list, decrementing its reference count and possibly deallocating it. The real danger is that innocent-looking operations may invoke arbitrary Python code which could do this; there is a code path which allows control to flow back to the user from a Py_DECREF() , so almost any operation is potentially dangerous.
A safe approach is to always use the generic operations (functions whose name begins with PyObject_ , PyNumber_ , PySequence_ or PyMapping_ ). These operations always increment the reference count of the object they return. This leaves the caller with the responsibility to call Py_DECREF() when they are done with the result; this soon becomes second nature.
Reference Count Details¶
The reference count behavior of functions in the Python/C API is best explained in terms of ownership of references. Ownership pertains to references, never to objects (objects are not owned: they are always shared). “Owning a reference” means being responsible for calling Py_DECREF on it when the reference is no longer needed. Ownership can also be transferred, meaning that the code that receives ownership of the reference then becomes responsible for eventually decref’ing it by calling Py_DECREF() or Py_XDECREF() when it’s no longer needed—or passing on this responsibility (usually to its caller). When a function passes ownership of a reference on to its caller, the caller is said to receive a new reference. When no ownership is transferred, the caller is said to borrow the reference. Nothing needs to be done for a borrowed reference .
Conversely, when a calling function passes in a reference to an object, there are two possibilities: the function steals a reference to the object, or it does not. Stealing a reference means that when you pass a reference to a function, that function assumes that it now owns that reference, and you are not responsible for it any longer.
Few functions steal references; the two notable exceptions are PyList_SetItem() and PyTuple_SetItem() , which steal a reference to the item (but not to the tuple or list into which the item is put!). These functions were designed to steal a reference because of a common idiom for populating a tuple or list with newly created objects; for example, the code to create the tuple (1, 2, "three") could look like this (forgetting about error handling for the moment; a better way to code this is shown below):
Here, PyLong_FromLong() returns a new reference which is immediately stolen by PyTuple_SetItem() . When you want to keep using an object although the reference to it will be stolen, use Py_INCREF() to grab another reference before calling the reference-stealing function.
Incidentally, PyTuple_SetItem() is the only way to set tuple items; PySequence_SetItem() and PyObject_SetItem() refuse to do this since tuples are an immutable data type. You should only use PyTuple_SetItem() for tuples that you are creating yourself.
Equivalent code for populating a list can be written using PyList_New() and PyList_SetItem() .
However, in practice, you will rarely use these ways of creating and populating a tuple or list. There’s a generic function, Py_BuildValue() , that can create most common objects from C values, directed by a format string. For example, the above two blocks of code could be replaced by the following (which also takes care of the error checking):
It is much more common to use PyObject_SetItem() and friends with items whose references you are only borrowing, like arguments that were passed in to the function you are writing. In that case, their behaviour regarding reference counts is much saner, since you don’t have to increment a reference count so you can give a reference away (“have it be stolen”). For example, this function sets all items of a list (actually, any mutable sequence) to a given item:
The situation is slightly different for function return values. While passing a reference to most functions does not change your ownership responsibilities for that reference, many functions that return a reference to an object give you ownership of the reference. The reason is simple: in many cases, the returned object is created on the fly, and the reference you get is the only reference to the object. Therefore, the generic functions that return object references, like PyObject_GetItem() and PySequence_GetItem() , always return a new reference (the caller becomes the owner of the reference).
It is important to realize that whether you own a reference returned by a function depends on which function you call only — the plumage (the type of the object passed as an argument to the function) doesn’t enter into it! Thus, if you extract an item from a list using PyList_GetItem() , you don’t own the reference — but if you obtain the same item from the same list using PySequence_GetItem() (which happens to take exactly the same arguments), you do own a reference to the returned object.
Here is an example of how you could write a function that computes the sum of the items in a list of integers; once using PyList_GetItem() , and once using PySequence_GetItem() .
Types¶
There are few other data types that play a significant role in the Python/C API; most are simple C types such as int , long , double and char * . A few structure types are used to describe static tables used to list the functions exported by a module or the data attributes of a new object type, and another is used to describe the value of a complex number. These will be discussed together with the functions that use them.
A signed integral type such that sizeof(Py_ssize_t) == sizeof(size_t) . C99 doesn’t define such a thing directly (size_t is an unsigned integral type). See PEP 353 for details. PY_SSIZE_T_MAX is the largest positive value of type Py_ssize_t .
Exceptions¶
The Python programmer only needs to deal with exceptions if specific error handling is required; unhandled exceptions are automatically propagated to the caller, then to the caller’s caller, and so on, until they reach the top-level interpreter, where they are reported to the user accompanied by a stack traceback.
For C programmers, however, error checking always has to be explicit. All functions in the Python/C API can raise exceptions, unless an explicit claim is made otherwise in a function’s documentation. In general, when a function encounters an error, it sets an exception, discards any object references that it owns, and returns an error indicator. If not documented otherwise, this indicator is either NULL or -1 , depending on the function’s return type. A few functions return a Boolean true/false result, with false indicating an error. Very few functions return no explicit error indicator or have an ambiguous return value, and require explicit testing for errors with PyErr_Occurred() . These exceptions are always explicitly documented.
Exception state is maintained in per-thread storage (this is equivalent to using global storage in an unthreaded application). A thread can be in one of two states: an exception has occurred, or not. The function PyErr_Occurred() can be used to check for this: it returns a borrowed reference to the exception type object when an exception has occurred, and NULL otherwise. There are a number of functions to set the exception state: PyErr_SetString() is the most common (though not the most general) function to set the exception state, and PyErr_Clear() clears the exception state.
The full exception state consists of three objects (all of which can be NULL ): the exception type, the corresponding exception value, and the traceback. These have the same meanings as the Python result of sys.exc_info() ; however, they are not the same: the Python objects represent the last exception being handled by a Python try … except statement, while the C level exception state only exists while an exception is being passed on between C functions until it reaches the Python bytecode interpreter’s main loop, which takes care of transferring it to sys.exc_info() and friends.
Note that starting with Python 1.5, the preferred, thread-safe way to access the exception state from Python code is to call the function sys.exc_info() , which returns the per-thread exception state for Python code. Also, the semantics of both ways to access the exception state have changed so that a function which catches an exception will save and restore its thread’s exception state so as to preserve the exception state of its caller. This prevents common bugs in exception handling code caused by an innocent-looking function overwriting the exception being handled; it also reduces the often unwanted lifetime extension for objects that are referenced by the stack frames in the traceback.
As a general principle, a function that calls another function to perform some task should check whether the called function raised an exception, and if so, pass the exception state on to its caller. It should discard any object references that it owns, and return an error indicator, but it should not set another exception — that would overwrite the exception that was just raised, and lose important information about the exact cause of the error.
A simple example of detecting exceptions and passing them on is shown in the sum_sequence() example above. It so happens that this example doesn’t need to clean up any owned references when it detects an error. The following example function shows some error cleanup. First, to remind you why you like Python, we show the equivalent Python code:
Here is the corresponding C code, in all its glory:
This example represents an endorsed use of the goto statement in C! It illustrates the use of PyErr_ExceptionMatches() and PyErr_Clear() to handle specific exceptions, and the use of Py_XDECREF() to dispose of owned references that may be NULL (note the ‘X’ in the name; Py_DECREF() would crash when confronted with a NULL reference). It is important that the variables used to hold owned references are initialized to NULL for this to work; likewise, the proposed return value is initialized to -1 (failure) and only set to success after the final call made is successful.
Embedding Python¶
The one important task that only embedders (as opposed to extension writers) of the Python interpreter have to worry about is the initialization, and possibly the finalization, of the Python interpreter. Most functionality of the interpreter can only be used after the interpreter has been initialized.
The basic initialization function is Py_Initialize() . This initializes the table of loaded modules, and creates the fundamental modules builtins , __main__ , and sys . It also initializes the module search path ( sys.path ).
Py_Initialize() does not set the “script argument list” ( sys.argv ). If this variable is needed by Python code that will be executed later, it must be set explicitly with a call to PySys_SetArgvEx(argc, argv, updatepath) after the call to Py_Initialize() .
On most systems (in particular, on Unix and Windows, although the details are slightly different), Py_Initialize() calculates the module search path based upon its best guess for the location of the standard Python interpreter executable, assuming that the Python library is found in a fixed location relative to the Python interpreter executable. In particular, it looks for a directory named lib/python X.Y relative to the parent directory where the executable named python is found on the shell command search path (the environment variable PATH ).
For instance, if the Python executable is found in /usr/local/bin/python , it will assume that the libraries are in /usr/local/lib/python X.Y . (In fact, this particular path is also the “fallback” location, used when no executable file named python is found along PATH .) The user can override this behavior by setting the environment variable PYTHONHOME , or insert additional directories in front of the standard path by setting PYTHONPATH .
The embedding application can steer the search by calling Py_SetProgramName(file) before calling Py_Initialize() . Note that PYTHONHOME still overrides this and PYTHONPATH is still inserted in front of the standard path. An application that requires total control has to provide its own implementation of Py_GetPath() , Py_GetPrefix() , Py_GetExecPrefix() , and Py_GetProgramFullPath() (all defined in Modules/getpath.c ).
Sometimes, it is desirable to “uninitialize” Python. For instance, the application may want to start over (make another call to Py_Initialize() ) or the application is simply done with its use of Python and wants to free memory allocated by Python. This can be accomplished by calling Py_FinalizeEx() . The function Py_IsInitialized() returns true if Python is currently in the initialized state. More information about these functions is given in a later chapter. Notice that Py_FinalizeEx() does not free all memory allocated by the Python interpreter, e.g. memory allocated by extension modules currently cannot be released.
Debugging Builds¶
Python can be built with several macros to enable extra checks of the interpreter and extension modules. These checks tend to add a large amount of overhead to the runtime so they are not enabled by default.
A full list of the various types of debugging builds is in the file Misc/SpecialBuilds.txt in the Python source distribution. Builds are available that support tracing of reference counts, debugging the memory allocator, or low-level profiling of the main interpreter loop. Only the most frequently used builds will be described in the remainder of this section.
Compiling the interpreter with the Py_DEBUG macro defined produces what is generally meant by a debug build of Python . Py_DEBUG is enabled in the Unix build by adding —with-pydebug to the ./configure command. It is also implied by the presence of the not-Python-specific _DEBUG macro. When Py_DEBUG is enabled in the Unix build, compiler optimization is disabled.
In addition to the reference count debugging described below, extra checks are performed, see Python Debug Build .
Defining Py_TRACE_REFS enables reference tracing (see the configure —with-trace-refs option ). When defined, a circular doubly linked list of active objects is maintained by adding two extra fields to every PyObject . Total allocations are tracked as well. Upon exit, all existing references are printed. (In interactive mode this happens after every statement run by the interpreter.)
1. Extending Python with C or C++¶
It is quite easy to add new built-in modules to Python, if you know how to program in C. Such extension modules can do two things that can’t be done directly in Python: they can implement new built-in object types, and they can call C library functions and system calls.
To support extensions, the Python API (Application Programmers Interface) defines a set of functions, macros and variables that provide access to most aspects of the Python run-time system. The Python API is incorporated in a C source file by including the header "Python.h" .
The compilation of an extension module depends on its intended use as well as on your system setup; details are given in later chapters.
The C extension interface is specific to CPython, and extension modules do not work on other Python implementations. In many cases, it is possible to avoid writing C extensions and preserve portability to other implementations. For example, if your use case is calling C library functions or system calls, you should consider using the ctypes module or the cffi library rather than writing custom C code. These modules let you write Python code to interface with C code and are more portable between implementations of Python than writing and compiling a C extension module.
1.1. A Simple Example¶
Let’s create an extension module called spam (the favorite food of Monty Python fans…) and let’s say we want to create a Python interface to the C library function system() 1. This function takes a null-terminated character string as argument and returns an integer. We want this function to be callable from Python as follows:
Begin by creating a file spammodule.c . (Historically, if a module is called spam , the C file containing its implementation is called spammodule.c ; if the module name is very long, like spammify , the module name can be just spammify.c .)
The first two lines of our file can be:
which pulls in the Python API (you can add a comment describing the purpose of the module and a copyright notice if you like).
Since Python may define some pre-processor definitions which affect the standard headers on some systems, you must include Python.h before any standard headers are included.
It is recommended to always define PY_SSIZE_T_CLEAN before including Python.h . See Extracting Parameters in Extension Functions for a description of this macro.
All user-visible symbols defined by Python.h have a prefix of Py or PY , except those defined in standard header files. For convenience, and since they are used extensively by the Python interpreter, "Python.h" includes a few standard header files: <stdio.h> , <string.h> , <errno.h> , and <stdlib.h> . If the latter header file does not exist on your system, it declares the functions malloc() , free() and realloc() directly.
The next thing we add to our module file is the C function that will be called when the Python expression spam.system(string) is evaluated (we’ll see shortly how it ends up being called):
There is a straightforward translation from the argument list in Python (for example, the single expression "ls -l" ) to the arguments passed to the C function. The C function always has two arguments, conventionally named self and args.
The self argument points to the module object for module-level functions; for a method it would point to the object instance.
The args argument will be a pointer to a Python tuple object containing the arguments. Each item of the tuple corresponds to an argument in the call’s argument list. The arguments are Python objects — in order to do anything with them in our C function we have to convert them to C values. The function PyArg_ParseTuple() in the Python API checks the argument types and converts them to C values. It uses a template string to determine the required types of the arguments as well as the types of the C variables into which to store the converted values. More about this later.
PyArg_ParseTuple() returns true (nonzero) if all arguments have the right type and its components have been stored in the variables whose addresses are passed. It returns false (zero) if an invalid argument list was passed. In the latter case it also raises an appropriate exception so the calling function can return NULL immediately (as we saw in the example).
1.2. Intermezzo: Errors and Exceptions¶
An important convention throughout the Python interpreter is the following: when a function fails, it should set an exception condition and return an error value (usually -1 or a NULL pointer). Exception information is stored in three members of the interpreter’s thread state. These are NULL if there is no exception. Otherwise they are the C equivalents of the members of the Python tuple returned by sys.exc_info() . These are the exception type, exception instance, and a traceback object. It is important to know about them to understand how errors are passed around.
The Python API defines a number of functions to set various types of exceptions.
The most common one is PyErr_SetString() . Its arguments are an exception object and a C string. The exception object is usually a predefined object like PyExc_ZeroDivisionError . The C string indicates the cause of the error and is converted to a Python string object and stored as the “associated value” of the exception.
Another useful function is PyErr_SetFromErrno() , which only takes an exception argument and constructs the associated value by inspection of the global variable errno . The most general function is PyErr_SetObject() , which takes two object arguments, the exception and its associated value. You don’t need to Py_INCREF() the objects passed to any of these functions.
You can test non-destructively whether an exception has been set with PyErr_Occurred() . This returns the current exception object, or NULL if no exception has occurred. You normally don’t need to call PyErr_Occurred() to see whether an error occurred in a function call, since you should be able to tell from the return value.
When a function f that calls another function g detects that the latter fails, f should itself return an error value (usually NULL or -1 ). It should not call one of the PyErr_* functions — one has already been called by g. f’s caller is then supposed to also return an error indication to its caller, again without calling PyErr_* , and so on — the most detailed cause of the error was already reported by the function that first detected it. Once the error reaches the Python interpreter’s main loop, this aborts the currently executing Python code and tries to find an exception handler specified by the Python programmer.
(There are situations where a module can actually give a more detailed error message by calling another PyErr_* function, and in such cases it is fine to do so. As a general rule, however, this is not necessary, and can cause information about the cause of the error to be lost: most operations can fail for a variety of reasons.)
To ignore an exception set by a function call that failed, the exception condition must be cleared explicitly by calling PyErr_Clear() . The only time C code should call PyErr_Clear() is if it doesn’t want to pass the error on to the interpreter but wants to handle it completely by itself (possibly by trying something else, or pretending nothing went wrong).
Every failing malloc() call must be turned into an exception — the direct caller of malloc() (or realloc() ) must call PyErr_NoMemory() and return a failure indicator itself. All the object-creating functions (for example, PyLong_FromLong() ) already do this, so this note is only relevant to those who call malloc() directly.
Also note that, with the important exception of PyArg_ParseTuple() and friends, functions that return an integer status usually return a positive value or zero for success and -1 for failure, like Unix system calls.
Finally, be careful to clean up garbage (by making Py_XDECREF() or Py_DECREF() calls for objects you have already created) when you return an error indicator!
The choice of which exception to raise is entirely yours. There are predeclared C objects corresponding to all built-in Python exceptions, such as PyExc_ZeroDivisionError , which you can use directly. Of course, you should choose exceptions wisely — don’t use PyExc_TypeError to mean that a file couldn’t be opened (that should probably be PyExc_IOError ). If something’s wrong with the argument list, the PyArg_ParseTuple() function usually raises PyExc_TypeError . If you have an argument whose value must be in a particular range or must satisfy other conditions, PyExc_ValueError is appropriate.
You can also define a new exception that is unique to your module. For this, you usually declare a static object variable at the beginning of your file:
and initialize it in your module’s initialization function ( PyInit_spam() ) with an exception object:
Note that the Python name for the exception object is spam.error . The PyErr_NewException() function may create a class with the base class being Exception (unless another class is passed in instead of NULL ), described in Built-in Exceptions .
Note also that the SpamError variable retains a reference to the newly created exception class; this is intentional! Since the exception could be removed from the module by external code, an owned reference to the class is needed to ensure that it will not be discarded, causing SpamError to become a dangling pointer. Should it become a dangling pointer, C code which raises the exception could cause a core dump or other unintended side effects.
We discuss the use of PyMODINIT_FUNC as a function return type later in this sample.
The spam.error exception can be raised in your extension module using a call to PyErr_SetString() as shown below:
1.3. Back to the Example¶
Going back to our example function, you should now be able to understand this statement:
It returns NULL (the error indicator for functions returning object pointers) if an error is detected in the argument list, relying on the exception set by PyArg_ParseTuple() . Otherwise the string value of the argument has been copied to the local variable command . This is a pointer assignment and you are not supposed to modify the string to which it points (so in Standard C, the variable command should properly be declared as const char *command ).
The next statement is a call to the Unix function system() , passing it the string we just got from PyArg_ParseTuple() :
Our spam.system() function must return the value of sts as a Python object. This is done using the function PyLong_FromLong() .
In this case, it will return an integer object. (Yes, even integers are objects on the heap in Python!)
If you have a C function that returns no useful argument (a function returning void ), the corresponding Python function must return None . You need this idiom to do so (which is implemented by the Py_RETURN_NONE macro):
Py_None is the C name for the special Python object None . It is a genuine Python object rather than a NULL pointer, which means “error” in most contexts, as we have seen.
1.4. The Module’s Method Table and Initialization Function¶
I promised to show how spam_system() is called from Python programs. First, we need to list its name and address in a “method table”:
Note the third entry ( METH_VARARGS ). This is a flag telling the interpreter the calling convention to be used for the C function. It should normally always be METH_VARARGS or METH_VARARGS | METH_KEYWORDS ; a value of 0 means that an obsolete variant of PyArg_ParseTuple() is used.
When using only METH_VARARGS , the function should expect the Python-level parameters to be passed in as a tuple acceptable for parsing via PyArg_ParseTuple() ; more information on this function is provided below.
The METH_KEYWORDS bit may be set in the third field if keyword arguments should be passed to the function. In this case, the C function should accept a third PyObject * parameter which will be a dictionary of keywords. Use PyArg_ParseTupleAndKeywords() to parse the arguments to such a function.
The method table must be referenced in the module definition structure:
This structure, in turn, must be passed to the interpreter in the module’s initialization function. The initialization function must be named PyInit_name() , where name is the name of the module, and should be the only non- static item defined in the module file:
Note that PyMODINIT_FUNC declares the function as PyObject * return type, declares any special linkage declarations required by the platform, and for C++ declares the function as extern "C" .
When the Python program imports module spam for the first time, PyInit_spam() is called. (See below for comments about embedding Python.) It calls PyModule_Create() , which returns a module object, and inserts built-in function objects into the newly created module based upon the table (an array of PyMethodDef structures) found in the module definition. PyModule_Create() returns a pointer to the module object that it creates. It may abort with a fatal error for certain errors, or return NULL if the module could not be initialized satisfactorily. The init function must return the module object to its caller, so that it then gets inserted into sys.modules .
When embedding Python, the PyInit_spam() function is not called automatically unless there’s an entry in the PyImport_Inittab table. To add the module to the initialization table, use PyImport_AppendInittab() , optionally followed by an import of the module:
Removing entries from sys.modules or importing compiled modules into multiple interpreters within a process (or following a fork() without an intervening exec() ) can create problems for some extension modules. Extension module authors should exercise caution when initializing internal data structures.
A more substantial example module is included in the Python source distribution as Modules/xxmodule.c . This file may be used as a template or simply read as an example.
Unlike our spam example, xxmodule uses multi-phase initialization (new in Python 3.5), where a PyModuleDef structure is returned from PyInit_spam , and creation of the module is left to the import machinery. For details on multi-phase initialization, see PEP 489.
1.5. Compilation and Linkage¶
There are two more things to do before you can use your new extension: compiling and linking it with the Python system. If you use dynamic loading, the details may depend on the style of dynamic loading your system uses; see the chapters about building extension modules (chapter Building C and C++ Extensions ) and additional information that pertains only to building on Windows (chapter Building C and C++ Extensions on Windows ) for more information about this.
If you can’t use dynamic loading, or if you want to make your module a permanent part of the Python interpreter, you will have to change the configuration setup and rebuild the interpreter. Luckily, this is very simple on Unix: just place your file ( spammodule.c for example) in the Modules/ directory of an unpacked source distribution, add a line to the file Modules/Setup.local describing your file:
and rebuild the interpreter by running make in the toplevel directory. You can also run make in the Modules/ subdirectory, but then you must first rebuild Makefile there by running ‘make Makefile’. (This is necessary each time you change the Setup file.)
If your module requires additional libraries to link with, these can be listed on the line in the configuration file as well, for instance:
1.6. Calling Python Functions from C¶
So far we have concentrated on making C functions callable from Python. The reverse is also useful: calling Python functions from C. This is especially the case for libraries that support so-called “callback” functions. If a C interface makes use of callbacks, the equivalent Python often needs to provide a callback mechanism to the Python programmer; the implementation will require calling the Python callback functions from a C callback. Other uses are also imaginable.
Fortunately, the Python interpreter is easily called recursively, and there is a standard interface to call a Python function. (I won’t dwell on how to call the Python parser with a particular string as input — if you’re interested, have a look at the implementation of the -c command line option in Modules/main.c from the Python source code.)
Calling a Python function is easy. First, the Python program must somehow pass you the Python function object. You should provide a function (or some other interface) to do this. When this function is called, save a pointer to the Python function object (be careful to Py_INCREF() it!) in a global variable — or wherever you see fit. For example, the following function might be part of a module definition:
This function must be registered with the interpreter using the METH_VARARGS flag; this is described in section The Module’s Method Table and Initialization Function . The PyArg_ParseTuple() function and its arguments are documented in section Extracting Parameters in Extension Functions .
The macros Py_XINCREF() and Py_XDECREF() increment/decrement the reference count of an object and are safe in the presence of NULL pointers (but note that temp will not be NULL in this context). More info on them in section Reference Counts .
Later, when it is time to call the function, you call the C function PyObject_CallObject() . This function has two arguments, both pointers to arbitrary Python objects: the Python function, and the argument list. The argument list must always be a tuple object, whose length is the number of arguments. To call the Python function with no arguments, pass in NULL , or an empty tuple; to call it with one argument, pass a singleton tuple. Py_BuildValue() returns a tuple when its format string consists of zero or more format codes between parentheses. For example:
PyObject_CallObject() returns a Python object pointer: this is the return value of the Python function. PyObject_CallObject() is “reference-count-neutral” with respect to its arguments. In the example a new tuple was created to serve as the argument list, which is Py_DECREF() -ed immediately after the PyObject_CallObject() call.
The return value of PyObject_CallObject() is “new”: either it is a brand new object, or it is an existing object whose reference count has been incremented. So, unless you want to save it in a global variable, you should somehow Py_DECREF() the result, even (especially!) if you are not interested in its value.
Before you do this, however, it is important to check that the return value isn’t NULL . If it is, the Python function terminated by raising an exception. If the C code that called PyObject_CallObject() is called from Python, it should now return an error indication to its Python caller, so the interpreter can print a stack trace, or the calling Python code can handle the exception. If this is not possible or desirable, the exception should be cleared by calling PyErr_Clear() . For example:
Depending on the desired interface to the Python callback function, you may also have to provide an argument list to PyObject_CallObject() . In some cases the argument list is also provided by the Python program, through the same interface that specified the callback function. It can then be saved and used in the same manner as the function object. In other cases, you may have to construct a new tuple to pass as the argument list. The simplest way to do this is to call Py_BuildValue() . For example, if you want to pass an integral event code, you might use the following code:
Note the placement of Py_DECREF(arglist) immediately after the call, before the error check! Also note that strictly speaking this code is not complete: Py_BuildValue() may run out of memory, and this should be checked.
You may also call a function with keyword arguments by using PyObject_Call() , which supports arguments and keyword arguments. As in the above example, we use Py_BuildValue() to construct the dictionary.
1.7. Extracting Parameters in Extension Functions¶
The PyArg_ParseTuple() function is declared as follows:
The arg argument must be a tuple object containing an argument list passed from Python to a C function. The format argument must be a format string, whose syntax is explained in Parsing arguments and building values in the Python/C API Reference Manual. The remaining arguments must be addresses of variables whose type is determined by the format string.
Note that while PyArg_ParseTuple() checks that the Python arguments have the required types, it cannot check the validity of the addresses of C variables passed to the call: if you make mistakes there, your code will probably crash or at least overwrite random bits in memory. So be careful!
Note that any Python object references which are provided to the caller are borrowed references; do not decrement their reference count!
Some example calls:
1.8. Keyword Parameters for Extension Functions¶
The PyArg_ParseTupleAndKeywords() function is declared as follows:
The arg and format parameters are identical to those of the PyArg_ParseTuple() function. The kwdict parameter is the dictionary of keywords received as the third parameter from the Python runtime. The kwlist parameter is a NULL -terminated list of strings which identify the parameters; the names are matched with the type information from format from left to right. On success, PyArg_ParseTupleAndKeywords() returns true, otherwise it returns false and raises an appropriate exception.
Nested tuples cannot be parsed when using keyword arguments! Keyword parameters passed in which are not present in the kwlist will cause TypeError to be raised.
Here is an example module which uses keywords, based on an example by Geoff Philbrick (philbrick @ hks . com):
1.9. Building Arbitrary Values¶
This function is the counterpart to PyArg_ParseTuple() . It is declared as follows:
It recognizes a set of format units similar to the ones recognized by PyArg_ParseTuple() , but the arguments (which are input to the function, not output) must not be pointers, just values. It returns a new Python object, suitable for returning from a C function called from Python.
One difference with PyArg_ParseTuple() : while the latter requires its first argument to be a tuple (since Python argument lists are always represented as tuples internally), Py_BuildValue() does not always build a tuple. It builds a tuple only if its format string contains two or more format units. If the format string is empty, it returns None ; if it contains exactly one format unit, it returns whatever object is described by that format unit. To force it to return a tuple of size 0 or one, parenthesize the format string.
Examples (to the left the call, to the right the resulting Python value):
1.10. Reference Counts¶
In languages like C or C++, the programmer is responsible for dynamic allocation and deallocation of memory on the heap. In C, this is done using the functions malloc() and free() . In C++, the operators new and delete are used with essentially the same meaning and we’ll restrict the following discussion to the C case.
Every block of memory allocated with malloc() should eventually be returned to the pool of available memory by exactly one call to free() . It is important to call free() at the right time. If a block’s address is forgotten but free() is not called for it, the memory it occupies cannot be reused until the program terminates. This is called a memory leak. On the other hand, if a program calls free() for a block and then continues to use the block, it creates a conflict with re-use of the block through another malloc() call. This is called using freed memory. It has the same bad consequences as referencing uninitialized data — core dumps, wrong results, mysterious crashes.
Common causes of memory leaks are unusual paths through the code. For instance, a function may allocate a block of memory, do some calculation, and then free the block again. Now a change in the requirements for the function may add a test to the calculation that detects an error condition and can return prematurely from the function. It’s easy to forget to free the allocated memory block when taking this premature exit, especially when it is added later to the code. Such leaks, once introduced, often go undetected for a long time: the error exit is taken only in a small fraction of all calls, and most modern machines have plenty of virtual memory, so the leak only becomes apparent in a long-running process that uses the leaking function frequently. Therefore, it’s important to prevent leaks from happening by having a coding convention or strategy that minimizes this kind of errors.
Since Python makes heavy use of malloc() and free() , it needs a strategy to avoid memory leaks as well as the use of freed memory. The chosen method is called reference counting. The principle is simple: every object contains a counter, which is incremented when a reference to the object is stored somewhere, and which is decremented when a reference to it is deleted. When the counter reaches zero, the last reference to the object has been deleted and the object is freed.
An alternative strategy is called automatic garbage collection. (Sometimes, reference counting is also referred to as a garbage collection strategy, hence my use of “automatic” to distinguish the two.) The big advantage of automatic garbage collection is that the user doesn’t need to call free() explicitly. (Another claimed advantage is an improvement in speed or memory usage — this is no hard fact however.) The disadvantage is that for C, there is no truly portable automatic garbage collector, while reference counting can be implemented portably (as long as the functions malloc() and free() are available — which the C Standard guarantees). Maybe some day a sufficiently portable automatic garbage collector will be available for C. Until then, we’ll have to live with reference counts.
While Python uses the traditional reference counting implementation, it also offers a cycle detector that works to detect reference cycles. This allows applications to not worry about creating direct or indirect circular references; these are the weakness of garbage collection implemented using only reference counting. Reference cycles consist of objects which contain (possibly indirect) references to themselves, so that each object in the cycle has a reference count which is non-zero. Typical reference counting implementations are not able to reclaim the memory belonging to any objects in a reference cycle, or referenced from the objects in the cycle, even though there are no further references to the cycle itself.
The cycle detector is able to detect garbage cycles and can reclaim them. The gc module exposes a way to run the detector (the collect() function), as well as configuration interfaces and the ability to disable the detector at runtime.
1.10.1. Reference Counting in Python¶
There are two macros, Py_INCREF(x) and Py_DECREF(x) , which handle the incrementing and decrementing of the reference count. Py_DECREF() also frees the object when the count reaches zero. For flexibility, it doesn’t call free() directly — rather, it makes a call through a function pointer in the object’s type object. For this purpose (and others), every object also contains a pointer to its type object.
The big question now remains: when to use Py_INCREF(x) and Py_DECREF(x) ? Let’s first introduce some terms. Nobody “owns” an object; however, you can own a reference to an object. An object’s reference count is now defined as the number of owned references to it. The owner of a reference is responsible for calling Py_DECREF() when the reference is no longer needed. Ownership of a reference can be transferred. There are three ways to dispose of an owned reference: pass it on, store it, or call Py_DECREF() . Forgetting to dispose of an owned reference creates a memory leak.
It is also possible to borrow 2 a reference to an object. The borrower of a reference should not call Py_DECREF() . The borrower must not hold on to the object longer than the owner from which it was borrowed. Using a borrowed reference after the owner has disposed of it risks using freed memory and should be avoided completely 3.
The advantage of borrowing over owning a reference is that you don’t need to take care of disposing of the reference on all possible paths through the code — in other words, with a borrowed reference you don’t run the risk of leaking when a premature exit is taken. The disadvantage of borrowing over owning is that there are some subtle situations where in seemingly correct code a borrowed reference can be used after the owner from which it was borrowed has in fact disposed of it.
A borrowed reference can be changed into an owned reference by calling Py_INCREF() . This does not affect the status of the owner from which the reference was borrowed — it creates a new owned reference, and gives full owner responsibilities (the new owner must dispose of the reference properly, as well as the previous owner).
1.10.2. Ownership Rules¶
Whenever an object reference is passed into or out of a function, it is part of the function’s interface specification whether ownership is transferred with the reference or not.
Most functions that return a reference to an object pass on ownership with the reference. In particular, all functions whose function it is to create a new object, such as PyLong_FromLong() and Py_BuildValue() , pass ownership to the receiver. Even if the object is not actually new, you still receive ownership of a new reference to that object. For instance, PyLong_FromLong() maintains a cache of popular values and can return a reference to a cached item.
Many functions that extract objects from other objects also transfer ownership with the reference, for instance PyObject_GetAttrString() . The picture is less clear, here, however, since a few common routines are exceptions: PyTuple_GetItem() , PyList_GetItem() , PyDict_GetItem() , and PyDict_GetItemString() all return references that you borrow from the tuple, list or dictionary.
The function PyImport_AddModule() also returns a borrowed reference, even though it may actually create the object it returns: this is possible because an owned reference to the object is stored in sys.modules .
When you pass an object reference into another function, in general, the function borrows the reference from you — if it needs to store it, it will use Py_INCREF() to become an independent owner. There are exactly two important exceptions to this rule: PyTuple_SetItem() and PyList_SetItem() . These functions take over ownership of the item passed to them — even if they fail! (Note that PyDict_SetItem() and friends don’t take over ownership — they are “normal.”)
When a C function is called from Python, it borrows references to its arguments from the caller. The caller owns a reference to the object, so the borrowed reference’s lifetime is guaranteed until the function returns. Only when such a borrowed reference must be stored or passed on, it must be turned into an owned reference by calling Py_INCREF() .
The object reference returned from a C function that is called from Python must be an owned reference — ownership is transferred from the function to its caller.
1.10.3. Thin Ice¶
There are a few situations where seemingly harmless use of a borrowed reference can lead to problems. These all have to do with implicit invocations of the interpreter, which can cause the owner of a reference to dispose of it.
The first and most important case to know about is using Py_DECREF() on an unrelated object while borrowing a reference to a list item. For instance:
This function first borrows a reference to list[0] , then replaces list[1] with the value 0 , and finally prints the borrowed reference. Looks harmless, right? But it’s not!
Let’s follow the control flow into PyList_SetItem() . The list owns references to all its items, so when item 1 is replaced, it has to dispose of the original item 1. Now let’s suppose the original item 1 was an instance of a user-defined class, and let’s further suppose that the class defined a __del__() method. If this class instance has a reference count of 1, disposing of it will call its __del__() method.
Since it is written in Python, the __del__() method can execute arbitrary Python code. Could it perhaps do something to invalidate the reference to item in bug() ? You bet! Assuming that the list passed into bug() is accessible to the __del__() method, it could execute a statement to the effect of del list[0] , and assuming this was the last reference to that object, it would free the memory associated with it, thereby invalidating item .
The solution, once you know the source of the problem, is easy: temporarily increment the reference count. The correct version of the function reads:
This is a true story. An older version of Python contained variants of this bug and someone spent a considerable amount of time in a C debugger to figure out why his __del__() methods would fail…
The second case of problems with a borrowed reference is a variant involving threads. Normally, multiple threads in the Python interpreter can’t get in each other’s way, because there is a global lock protecting Python’s entire object space. However, it is possible to temporarily release this lock using the macro Py_BEGIN_ALLOW_THREADS , and to re-acquire it using Py_END_ALLOW_THREADS . This is common around blocking I/O calls, to let other threads use the processor while waiting for the I/O to complete. Obviously, the following function has the same problem as the previous one:
1.10.4. NULL Pointers¶
In general, functions that take object references as arguments do not expect you to pass them NULL pointers, and will dump core (or cause later core dumps) if you do so. Functions that return object references generally return NULL only to indicate that an exception occurred. The reason for not testing for NULL arguments is that functions often pass the objects they receive on to other function — if each function were to test for NULL , there would be a lot of redundant tests and the code would run more slowly.
It is better to test for NULL only at the “source:” when a pointer that may be NULL is received, for example, from malloc() or from a function that may raise an exception.
The macros Py_INCREF() and Py_DECREF() do not check for NULL pointers — however, their variants Py_XINCREF() and Py_XDECREF() do.
The macros for checking for a particular object type ( Pytype_Check() ) don’t check for NULL pointers — again, there is much code that calls several of these in a row to test an object against various different expected types, and this would generate redundant tests. There are no variants with NULL checking.
The C function calling mechanism guarantees that the argument list passed to C functions ( args in the examples) is never NULL — in fact it guarantees that it is always a tuple 4.
It is a severe error to ever let a NULL pointer “escape” to the Python user.
1.11. Writing Extensions in C++¶
It is possible to write extension modules in C++. Some restrictions apply. If the main program (the Python interpreter) is compiled and linked by the C compiler, global or static objects with constructors cannot be used. This is not a problem if the main program is linked by the C++ compiler. Functions that will be called by the Python interpreter (in particular, module initialization functions) have to be declared using extern "C" . It is unnecessary to enclose the Python header files in extern "C" <. >— they use this form already if the symbol __cplusplus is defined (all recent C++ compilers define this symbol).
1.12. Providing a C API for an Extension Module¶
Many extension modules just provide new functions and types to be used from Python, but sometimes the code in an extension module can be useful for other extension modules. For example, an extension module could implement a type “collection” which works like lists without order. Just like the standard Python list type has a C API which permits extension modules to create and manipulate lists, this new collection type should have a set of C functions for direct manipulation from other extension modules.
At first sight this seems easy: just write the functions (without declaring them static , of course), provide an appropriate header file, and document the C API. And in fact this would work if all extension modules were always linked statically with the Python interpreter. When modules are used as shared libraries, however, the symbols defined in one module may not be visible to another module. The details of visibility depend on the operating system; some systems use one global namespace for the Python interpreter and all extension modules (Windows, for example), whereas others require an explicit list of imported symbols at module link time (AIX is one example), or offer a choice of different strategies (most Unices). And even if symbols are globally visible, the module whose functions one wishes to call might not have been loaded yet!
Portability therefore requires not to make any assumptions about symbol visibility. This means that all symbols in extension modules should be declared static , except for the module’s initialization function, in order to avoid name clashes with other extension modules (as discussed in section The Module’s Method Table and Initialization Function ). And it means that symbols that should be accessible from other extension modules must be exported in a different way.
Python provides a special mechanism to pass C-level information (pointers) from one extension module to another one: Capsules. A Capsule is a Python data type which stores a pointer ( void * ). Capsules can only be created and accessed via their C API, but they can be passed around like any other Python object. In particular, they can be assigned to a name in an extension module’s namespace. Other extension modules can then import this module, retrieve the value of this name, and then retrieve the pointer from the Capsule.
There are many ways in which Capsules can be used to export the C API of an extension module. Each function could get its own Capsule, or all C API pointers could be stored in an array whose address is published in a Capsule. And the various tasks of storing and retrieving the pointers can be distributed in different ways between the module providing the code and the client modules.
Whichever method you choose, it’s important to name your Capsules properly. The function PyCapsule_New() takes a name parameter ( const char * ); you’re permitted to pass in a NULL name, but we strongly encourage you to specify a name. Properly named Capsules provide a degree of runtime type-safety; there is no feasible way to tell one unnamed Capsule from another.
In particular, Capsules used to expose C APIs should be given a name following this convention:
The convenience function PyCapsule_Import() makes it easy to load a C API provided via a Capsule, but only if the Capsule’s name matches this convention. This behavior gives C API users a high degree of certainty that the Capsule they load contains the correct C API.
The following example demonstrates an approach that puts most of the burden on the writer of the exporting module, which is appropriate for commonly used library modules. It stores all C API pointers (just one in the example!) in an array of void pointers which becomes the value of a Capsule. The header file corresponding to the module provides a macro that takes care of importing the module and retrieving its C API pointers; client modules only have to call this macro before accessing the C API.
The exporting module is a modification of the spam module from section A Simple Example . The function spam.system() does not call the C library function system() directly, but a function PySpam_System() , which would of course do something more complicated in reality (such as adding “spam” to every command). This function PySpam_System() is also exported to other extension modules.
The function PySpam_System() is a plain C function, declared static like everything else:
Вступление¶
Интерфейс прикладного программирования для Python предоставляет C и C++ программистам доступ к интерпретатору Python на различных уровнях. API также можно использовать с C++, но для краткости его обычно называют Python/C API. Есть две принципиально разные причины использования API Python/C. Первая причина — разработка модулей расширения для определенных целей; это модули C, расширяющие интерпретатор Python. Это, вероятно, наиболее распространённое использование. Вторая причина — использовать Python как компонент в более крупном приложении; данный метод обычно используется при встраивании Python в приложение.
Написание модуля расширения — это относительно хорошо понятный процесс, в котором хорошо работает подход «поваренной книги». Есть несколько инструментов, которые в некоторой степени автоматизируют данный процесс. Хотя люди встраивали Python в другие приложения с самого начала его существования, процесс встраивания Python менее прост, чем написание расширения.
Многие функции API полезны независимо от того, встраиваете ли вы Python или расширяете его; более того, большинство приложений, которые встраивают Python, также должны предоставлять собственное расширение, поэтому, вероятно, будет хорошей идеей ознакомиться с написанием расширения, прежде чем пытаться встроить Python в реальное приложение.
Стандарты кодирования¶
Если вы пишете код C для включения в CPython, вы должены следовать рекомендациям и стандартам, определённым в PEP 7. Эти правила применяются независимо от версии Python, над которой вы работаете. Соблюдение этих соглашений не является обязательным для ваших собственных сторонних модулей расширения, если вы в конечном итоге не планируете вносить их в Python.
Подключение файлов¶
Все определения функций, типов и макросов, необходимые для использования Python/C API, подключаются в ваш код следующей строкой:
Это подразумевает подключение следующих стандартных заголовков: <stdio.h> , <string.h> , <errno.h> , <limits.h> , <assert.h> и <stdlib.h> (при наличии).
Поскольку Python может определять некоторые определения препроцессора, которые влияют на стандартные заголовки в некоторых системах, вы должны подключать Python.h перед подключением любых стандартных заголовков.
Перед подключением Python.h рекомендуется всегда определять PY_SSIZE_T_CLEAN . См. описание этого макроса в Анализ аргументов и сборка значений .
Все видимые пользователем имена, определённые Python.h (кроме тех, которые определены включенными стандартными заголовками), содержат один из префиксов Py или _Py . Имена, начинающиеся с _Py , предназначены для внутреннего использования реализацией Python и не должны использоваться разработчиками расширений. У имёна членов структуры нет зарезервированного префикса.
Пользовательский код не должен определять имена, начинающиеся с Py или _Py . Это сбивает читателя с толку и ставит под угрозу переносимость пользовательского кода для будущих версий Python, которые могут определять дополнительные имена, начинающиеся с одного из этих префиксов.
Файлы заголовков обычно устанавливаются вместе с Python. В Unix они расположены в каталогах prefix /include/pythonversion/ и exec_prefix /include/pythonversion/ , где prefix и exec_prefix определяются соответствующими параметрами сценария Python configure, а version — ‘%d.%d’ % sys.version_info[:2] . В Windows заголовки устанавливаются в prefix /include , где prefix — это каталог установки, указанный для установщика.
Чтобы включить заголовки, поместите оба каталога (если они разные) в путь поиска вашего компилятора для include. Не помещайте родительские каталоги в путь поиска, а затем использовать #include <pythonX.Y/Python.h> ; это не работает в многоплатформенных сборках, поскольку независимые от платформы заголовки в prefix включают в себя специфичные для платформы заголовки из exec_prefix .
Пользователи C++ должны учитывать, что, хотя API полностью определён с использованием C, файлы заголовков правильно объявляют точки входа как extern «C» . В результате для использования API из C++ не нужно делать ничего особенного.
Полезные макросы¶
Несколько полезных макросов определены в файлах заголовков Python. Многие из них определены ближе к тому месту, где они могут быть полезны (например, Py_RETURN_NONE ). Здесь определяются другие, более общие полезности. Это не обязательно полный список.
Используйте его, если у вас есть путь кода, который вы не ожидаете достичь. Например, в предложении default: в операторе switch , для которого все возможные значения описаны в операторах case . Используйте его там, где у вас может возникнуть соблазн отправить вызов assert(0) или abort() .
Добавлено в версии 3.7.
Возвращает абсолютное значение x .
Добавлено в версии 3.3.
Возвращает минимальное значение от x до y .
Добавлено в версии 3.3.
Возвращает максимальное значение между x и y .
Добавлено в версии 3.3.
Преобразовать x в строку C. Например. Py_STRINGIFY(123) возвращает «123» .
Добавлено в версии 3.4.
Возвращает размер структуры ( type ) member в байтах.
Добавлено в версии 3.6.
Аргумент должен быть символом или целым числом в диапазоне [-128, 127] или [0, 255]. Данный макрос возвращает преобразование c в unsigned char .
Подобно getenv(s) , но возвращает NULL , если -E был передан в командной строке (т. е. если задано Py_IgnoreEnvironmentFlag ).
Используйте его для неиспользуемых аргументов в определении функции, чтобы отключить предупреждения компилятора. Пример: int func(int a, int Py_UNUSED(b)) < return a; >.
Добавлено в версии 3.4.
Используйте его для устаревших объявлений. Макрос должен быть помещён перед именем символа.
Изменено в версии 3.8: Добавлена поддержка MSVC.
Создаёт переменную с именем name , которую можно использовать в строках документации. Если Python построен без строк документации, значение будет пустым.
Использовать PyDoc_STRVAR для строк документации, чтобы поддерживать сборку Python без строк документации, как указано в PEP 7.
Создаёт строку документации для данной входной строки или пустую строку, если строки документации отключены.
Использовать PyDoc_STR при указании строк документации для поддержки сборки Python без строк документации, как указано в PEP 7.
Объекты, типы и количество ссылок¶
У большинства функций API Python/C один или несколько аргументов, а также возвращаемое значение типа PyObject* . Данный тип является указателем на непрозрачный тип данных, представляющий произвольный объект Python. Поскольку все типы объектов Python обрабатываются языком Python одинаково в большинстве ситуаций (например, присваивания, правила области видимости и передача аргументов), вполне уместно, чтобы они были представлены одним типом C. Почти все объекты Python находятся в куче: вы никогда не объявляете автоматическую или статическую переменную типа PyObject , можно объявить только переменные-указатели типа PyObject* . Единственное исключение — это объекты типа; поскольку их никогда нельзя освобождать, они обычно являются статическими объектами PyTypeObject .
У всех объектов Python (даже целые числа Python) есть тип и количество ссылок. Тип объекта определяет, что это за объект (например, целое число, список или определяемая пользователем функция; их гораздо больше, как приведено в Стандартная иерархия типов ). Для каждого из хорошо известных типов существует макрос, проверяющий, принадлежит ли объект этому типу; например, PyList_Check(a) истинно, если (и только если) объект, на который указывает a, является списком Python.
Количество ссылок¶
Подсчёт ссылок важен, потому что у современных компьютеров есть конечный (и часто сильно ограниченный) размер памяти; он подсчитывает, у скольких разных мест есть ссылка на объект. Таким местом может быть другой объект, или глобальная (или статическая) C переменная, или локальная переменная в некоторой C функции. Когда счётчик ссылок на объект становится равным нулю, объект освобождается. Если он содержит ссылки на другие объекты, их счётчик ссылок уменьшается. Другие объекты могут быть освобождены по очереди, если это декремент сделает их счётчик ссылок равным нулю, и так далее. (Здесь очевидная проблема с объектами, которые ссылаются друг на друга; на данный момент решение: «Не делайте этого».
Счётчиками ссылок всегда манипулируют явно. Обычный способ — использовать макрос Py_INCREF() для увеличения счётчика ссылок объекта на единицу и Py_DECREF() для уменьшения его на единицу. Макрос Py_DECREF() значительно сложнее макроса incref, поскольку он должен проверять, становится ли счётчик ссылок нулем, а затем вызывать освобождение объекта. Освободитель — это указатель на функцию, содержащийся в структуре типа объекта. Освободитель для конкретного типа заботится об уменьшении счётчиков ссылок для других объектов, содержащихся в объекте, если это составной тип объекта, например, список, а также выполняет любую дополнительную необходимую финализацию. Нет никаких шансов, что счётчик ссылок может переполниться; для хранения счётчика ссылок используется по крайней мере столько же битов, сколько существует различных ячеек памяти в виртуальной памяти (при условии sizeof(Py_ssize_t) >= sizeof(void*) ). Таким образом, увеличение счётчика ссылок — простая операция.
Нет необходимости увеличивать счётчик ссылок объекта для каждой локальной переменной, содержащей указатель на объект. Теоретически счётчик ссылок на объект увеличивается на единицу, когда переменная указывает на него, и уменьшается на единицу, когда переменная выходит за пределы области видимости. Однако эти двое взаимно компенсируют друг друга, поэтому в конце счётчик ссылок не изменился. Единственная реальная причина использовать счётчик ссылок — предотвратить освобождение объекта, пока наша переменная указывает на него. Если мы знаем, что существует хотя бы одна другая ссылка на объект, который живет по крайней мере столько же, сколько наша переменная, нет необходимости временно увеличивать счётчик ссылок. Важная ситуация, когда это возникает, — это объекты, которые передаются в качестве аргументов функциям C в модуле расширения, который вызывается из Python; механизм вызова гарантирует сохранение ссылки на каждый аргумент в течение всего вызова.
Однако распространенной ошибкой является извлечение объекта из списка и удержание его в течение некоторого времени без увеличения его счётчика ссылок. Другая операция могла бы предположительно удалить объект из списка, уменьшив его счётчик ссылок и, возможно, освободив его. Реальная опасность состоит в том, что невинно выглядящие операции могут вызвать произвольный код Python, который может это сделать; существует кодовый путь, который позволяет передавать управление обратно пользователю с Py_DECREF() , поэтому практически любая операция потенциально опасна.
Безопасный подход — всегда использовать общие операции (функции, имена которых начинаются с PyObject_ , PyNumber_ , PySequence_ или PyMapping_ ). Данные операции всегда увеличивают счётчик ссылок возвращаемого объекта. Это оставляет вызывающему ответственность вызвать Py_DECREF() , когда они закончат работу с результатом; это скоро становится второй натурой.
Сведения о количестве ссылок¶
Поведение функций в Python/C API счётчика ссылок лучше всего объясняется в терминах владение ссылками. Владение относится к ссылкам, а не к объектам (объекты не принадлежат: они всегда являются общими). «Владение ссылкой» означает ответственность за вызов Py_DECREF для неё, когда ссылка больше не нужна. Право владения также может быть передано, что означает, что код, который получает право собственности на ссылку, затем становится ответственным за её окончательное уменьшение, вызывая Py_DECREF() или Py_XDECREF() , когда она больше не нужна ,— или передавая эту ответственность (обычно вызывающей стороне). Когда функция передаёт владение на ссылку своему вызывающему, говорят, что вызывающий получает новую ссылку. Когда владение не передаётся, вызывающий одалживает ссылку. Для заимствованной ссылки ничего делать не нужно.
И наоборот, когда вызывающая функция передаёт ссылку на объект, есть две возможности: функция крадёт ссылку на объект или нет. Кража ссылки означает, что когда вы передаёте ссылку на функцию, эта функция предполагает, что теперь она владеет этой ссылкой, и вы больше не несете за неё ответственности.
Некоторые функции крадут ссылки; двумя примечательными исключениями являются PyList_SetItem() и PyTuple_SetItem() , которые крадут ссылку на элемент (но не на кортеж или список, в который данный элемент помещён!). Данные функции были разработаны для кражи ссылки из-за общей идиомы для заполнения кортежа или списка вновь созданными объектами; например, код для создания кортежа (1, 2, «three») может выглядеть следующим образом (забыв на данный момент об обработке ошибок; лучший способ кодирования этого показан ниже):
Здесь PyLong_FromLong() возвращает новую ссылку, которая сразу же украдена PyTuple_SetItem() . Если вы хотите продолжить использование объекта, хотя ссылка на него будет украдена, использовать Py_INCREF() , чтобы захватить другую ссылку перед вызовом функции кражи ссылок.
Между прочим, PyTuple_SetItem() — это способ только для установки элементов кортежа; PySequence_SetItem() и PyObject_SetItem() отказываются делать это, поскольку кортежи являются неизменяемым типом данных. Вы должны использовать PyTuple_SetItem() только для кортежей, которые вы создаёте сами.
Эквивалентный код для заполнения списка можно записать с использованием PyList_New() и PyList_SetItem() .
Однако на практике вы редко будете использовать эти способы создания и заполнения кортежа или списка. Существует общая функция Py_BuildValue() , которая может создавать наиболее распространенные объекты из значений C, управляемых строкой форматирования. Например, два вышеуказанных блока кода могут быть заменены следующим (который также заботится о проверке ошибок):
Гораздо более распространено использование PyObject_SetItem() и друзей с элементами, ссылки на которые вы только заимствуете, например, аргументы, которые были переданы функции, которую вы пишете. В этом случае их поведение в отношении счётчиков ссылок намного разумнее, поскольку вам не нужно увеличивать счётчик ссылок, чтобы вы могли передать ссылку («пусть она будет украдена»). Например, эта функция устанавливает все элементы списка (фактически, любую изменяемую последовательность) на данный элемент:
Ситуация несколько иная для значений, возвращаемых функцией. Хотя передача ссылки на большинство функций не изменяет ваши обязанности владения этой ссылкой, многие функции, возвращающие ссылку на объект, предоставляют вам право владения ссылкой. Причина проста: во многих случаях возвращаемый объект создаётся «на лету», и полученная ссылка является единственной ссылкой на объект. Поэтому универсальные функции, возвращающие ссылки на объекты, такие как PyObject_GetItem() и PySequence_GetItem() , всегда возвращают новую ссылку (вызывающий становится владельцем ссылки).
Важно понимать, что то, владеете ли вы ссылкой, возвращаемой функцией, зависит от того, какую функцию вы вызываете, только оперение (тип объекта, переданного в качестве аргумента функции) в него не входит! Таким образом, если вы извлекаете элемент из списка с помощью PyList_GetItem() , вы не владеете ссылкой ,— но если вы получаете тот же элемент из того же списка с помощью PySequence_GetItem() (который принимает точно такие же аргументы), вы владеете ссылкой на возвращённый объект.
Вот пример того, как вы могли бы написать функцию, которая вычисляет сумму элементов в списке целых чисел; один раз с использованием PyList_GetItem() и один раз с помощью PySequence_GetItem() .
Есть несколько других типов данных, которые играют важную роль в API Python/C; большинство из них — простые типы C, такие как int , long , double и char* . Несколько типов структур используются для описания статических таблиц, используемых для перечисления функций, экспортируемых модулем, или атрибутов данных нового типа объекта, а другой используется для описания значения комплексного числа. Они будут обсуждаться вместе с функциями, которые их используют.
Исключения¶
Программисту Python нужно работать с исключениями только в том случае, если требуется конкретная обработка ошибок; необработанные исключения автоматически передаются вызывающей стороне, затем вызывающей стороне и так далее, пока они не достигнут интерпретатора верхнего уровня, где они сообщаются пользователю в сопровождении трассировки стека.
Однако для программистов на C проверка ошибок всегда должна быть явной. Все функции в Python/C API могут вызывать исключения, если иное явно не указано в документации функции. Обычно, когда функция обнаруживает ошибку, она устанавливает исключение, отбрасывает любые ссылки на объекты, которыми она владеет, и возвращает индикатор ошибки. Если не указано иное, это индикатор NULL или -1 , в зависимости от типа возвращаемого значения функции. Некоторые функции возвращают логический результат «истина/ложь», где ложь указывает на ошибку. Очень немногие функции не возвращают явного индикатора ошибки или имеют неоднозначное возвращаемое значение и требуют явного тестирования на наличие ошибок с помощью PyErr_Occurred() . Данные исключения всегда явно документируются.
Состояние исключения поддерживается в хранилище для каждого потока (это эквивалентно использованию глобального хранилища в приложении без потоков). Поток может находиться в одном из двух состояний: возникло исключение или нет. Для проверки этого можно использовать функцию PyErr_Occurred() : она возвращает заимствованную ссылку на объект типа исключения, когда возникло исключение, и NULL в противном случае. Существует ряд функций для установки состояния исключения: PyErr_SetString() — наиболее распространенная (хотя и не самая общая) функция для установки состояния исключения, а PyErr_Clear() очищает состояние исключения.
Состояние полного исключения состоит из трёх объектов (каждый из которых может быть NULL ): тип исключения, соответствующее значение исключения и трассировка. Они имеют то же значение, что и результат Python sys.exc_info() ; однако они не совпадают: объекты Python представляют собой последнее исключение, обрабатываемое оператором Python try … except , в то время как состояние исключения уровня C существует только тогда, когда исключение передаётся между функциями C, пока оно не достигнет Python основной цикл интерпретатора байт-кода, который заботится о передаче его sys.exc_info() и его друзьям.
Обратите внимание, что начиная с Python 1.5 предпочтительным поточно- ориентированным способом доступа к состоянию исключения из кода Python является вызов функции sys.exc_info() , которая возвращает состояние исключения для каждого потока для кода Python. Кроме того, семантика обоих способов доступа к состоянию исключения изменилась, так что функция, перехватывающая исключение, будет сохранять и восстанавливать состояние исключения своего потока, чтобы сохранить состояние исключения вызывающей стороны. Это предотвращает распространенные ошибки в коде обработки исключений, вызванные невинно выглядящей функцией, перезаписывающей обрабатываемое исключение; это также уменьшает часто нежелательное продление срока службы для объектов, на которые ссылаются фреймы стека в трассировке.
Как правило, функция, которая вызывает другую функцию для выполнения некоторой задачи, должна проверять, вызвала ли вызываемая функция исключение, и, если да, передать состояние исключения вызывающей стороне. Она должна отбросить любые ссылки на объекты, которыми она владеет, и вернуть индикатор ошибки, но она не должна установить другое исключение, — которое перезапишет только что возникшее исключение и потеряет важную информацию о точной причине ошибки.
Простой пример обнаружения исключений и их передачи показан в примере sum_sequence() выше. Так получилось, что в этом примере не нужно очищать какие-либо собственные ссылки при обнаружении ошибки. В следующем примере функции показана некоторая очистка от ошибок. Во-первых, чтобы напомнить вам, почему вам нравится Python, мы показываем эквивалентный код Python:
Вот соответствующий C код во всей красе:
Данный пример представляет одобренное использование оператора goto в C! Он иллюстрирует использование PyErr_ExceptionMatches() и PyErr_Clear() для обработки определенных исключений и использование Py_XDECREF() для удаления собственных ссылок, которые могут быть NULL (обратите внимание на ‘X’ в имени; Py_DECREF() вылетит при столкновении со ссылкой NULL ). Важно, чтобы переменные, используемые для хранения собственных ссылок, были инициализированы как NULL , чтобы это работало; аналогично, предлагаемое возвращаемое значение инициализируется как -1 (сбой) и устанавливается на успех только после того, как последний сделанный вызов будет успешным.
Встраивание Python¶
Одна важная задача, о которой должны беспокоиться только разработчики (в отличие от разработчиков расширений) интерпретатора Python — это инициализация и, возможно, финализация интерпретатора Python. Большинство функций интерпретатора можно использовать только после его инициализации.
Основная функция инициализации — Py_Initialize() . Она инициализирует таблицу загруженных модулей и создаёт основные модули builtins , __main__ и sys . Она также инициализирует путь поиска модуля ( sys.path ).
Py_Initialize() не устанавливает «список аргументов сценария» ( sys.argv ). Если эта переменная необходима для кода Python, который будет выполнен позже, она должна быть явно установлена с помощью вызова PySys_SetArgvEx(argc, argv, updatepath) после вызова Py_Initialize() .
В большинстве систем (в частности, в Unix и Windows, хотя детали немного отличаются), Py_Initialize() вычисляет путь поиска модуля на основе наилучшего предположения о местонахождении стандартного исполняемого файла интерпретатора Python, предполагая, что библиотека Python находится в фиксированное расположение относительно исполняемого файла интерпретатора Python. В частности, она ищет каталог с именем lib/python X.Y относительно родительского каталога, где исполняемый файл с именем python находится в пути поиска команд оболочки (переменная среды PATH ).
Например, если исполняемый файл Python находится в /usr/local/bin/python , предполагается, что библиотеки находятся в /usr/local/lib/python X.Y . (Фактически, данный конкретный путь также является «резервным» местоположением, используемым, когда исполняемый файл с именем python не найден в PATH .) Пользователь может переопределить это поведение, установив переменную среды PYTHONHOME или вставив дополнительные каталоги перед стандартными путями, установив PYTHONPATH .
Приложение для встраивания может управлять поиском, вызвав перед Py_SetProgramName(file) и вызвав Py_Initialize() . Обратите внимание, что PYTHONHOME по-прежнему отменяет это, а PYTHONPATH по-прежнему вставляется перед стандартным путём. Приложение, требующее полного контроля, должно предоставлять собственную реализацию Py_GetPath() , Py_GetPrefix() , Py_GetExecPrefix() и Py_GetProgramFullPath() (все они определены в Modules/getpath.c ).
Иногда желательно «деинициализировать» Python. Например, приложение может захотеть начать заново (сделать ещё один вызов Py_Initialize() ) или приложение просто работает с использованием Python и хочет освободить память, выделенную Python. Это можно сделать, вызвав Py_FinalizeEx() . Функция Py_IsInitialized() возвращает истину, если Python в настоящий момент находится в инициализированном состоянии. Более подробная информация об этих функциях приведена в следующей главе. Обратите внимание, что Py_FinalizeEx() не освобождает всю память, выделенную интерпретатором Python, например память, выделенная модулями расширения, в настоящее время не может быть освобождена.
Отладка сборок¶
Python может быть построен с несколькими макросами, чтобы включить дополнительные проверки модулей интерпретатора и расширения. Эти проверки, как правило, увеличивают нагрузку на среду выполнения, поэтому по умолчанию они не включены.
Полный список различных типов отладочных сборок находится в файле Misc/SpecialBuilds.txt в дистрибутиве исходного кода Python. Доступны сборки, поддерживающие отслеживание счётчиков ссылок, отладку распределителя памяти или низкоуровневое профилирование основного цикла интерпретатора. В оставшейся части этого раздела будут описаны только наиболее часто используемые сборки.
Компиляция интерпретатора с определенным макросом Py_DEBUG предоставляет то, что обычно понимается под «отладочной сборкой» Python. Py_DEBUG включается в сборке Unix путем добавления —with-pydebug к команде ./configure . Это также подразумевается наличием не специфичного для Python макроса _DEBUG . Когда в сборке Unix включён Py_DEBUG , оптимизация компилятора отключена.
В дополнение к отладке счётчика ссылок, описанной ниже, выполняются следующие дополнительные проверки:
- В распределитель объектов добавляются дополнительные проверки.
- В парсер и компилятор добавлены дополнительные проверки.
- Отклонения от широких типов к узким проверяются на предмет потери информации.
- В словарь и множество реализаций добавлен ряд утверждений. Кроме того, установленный объект получает метод test_c_api() .
- При создании фрейма добавлены проверки корректности входных аргументов.
- Хранилище для целых чисел инициализируется известным недопустимым шаблоном для перехвата ссылки на неинициализированные цифры.
- В виртуальную машину среды выполнения добавлены низкоуровневая трассировка и дополнительная проверка исключений.
- В реализацию арены памяти добавлены дополнительные проверки.
- В модуль потока добавлена дополнительная отладка.
Могут быть дополнительные проверки, не упомянутые здесь.
Определение Py_TRACE_REFS включает трассировку ссылок. Если определено, круговой двусвязный список активных объектов поддерживается путём добавления двух дополнительных полей к каждому PyObject . Также отслеживаются общие распределения. При выходе печатаются все существующие ссылки. (В интерактивном режиме это происходит после каждого оператора, выполняемого интерпретатором.) Подразумевается Py_DEBUG .