Extending and Embedding Python, Release 3.9.5 19 2.1. Extending Python with C or C++ 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 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. 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). It is a severe error to ever let a$_{NULL}$ pointer “escape” to the Python user. 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}$. 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 macros $_{Py_INCREF()}$and Py_DECREF() do not check for NULL pointers — however, their variants $_{Py_XINCREF()}$and$_{Py_XDECREF()}$ do. 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. 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. NULL Pointers 2.1.11 Writing Extensions in C++ 2.1.12 Providing a C API for an Extension Module 4 These guarantees don’t hold when you use the “old” style calling convention — this is still found in much existing code. use the processor while waiting for the I/O to complete. Obviously, the following function has the same problem as the previous one: void bug(PyObject*list) { PyObject *item =PyList_GetItem(list,0); Py_BEGIN_ALLOW_THREADS ...some blocking I /O call... Py_END_ALLOW_THREADS PyObject_Print(item, stdout, 0); /* BUG! */ }