Extending & Embedding Python Using C - A First Module |
Written by Mike James | ||||
Tuesday, 05 March 2024 | ||||
Page 1 of 3 Your first module is always hardest to get working. Not if you follow our instructions. This is an extract from the new book by Mike James that helps you combine the speed and power of C with the versatility and ease-of-programming of Python. Extending & Embedding Python Using CBy Mike JamesBuy from Amazon. ContentsPreface
<ASIN:B0CK3X93KF> Module BasicsNow that we know how to build a module, the time has come to discover what goes into coding a module. Mostly this is a matter of making use of the C API and this is the subject of most of this book. There are some basic things that you have to do to make a C program into a module and this is where we start our examination of the API. The API and PyObjectThe Python C API is a collection of functions and “objects” with names that start Py or _Py. The ones named Py form the public API and you can use them. The ones named _Py are supposed to be private and you shouldn’t use them. The most important principle to understand is that everything in Python is represented in the C API as a PyObject – integers, lists, dictionary, functions, everything. The PyObject is a struct that contains very little information about the object – a reference count, see later, and a pointer to a type object which describes the object in question. A PyObject pointer can reference any Python object, but to make use of the object you may have to cast to a more specific type. The principle is that all Python objects are represented by a specific C struct that is an extension of PyObject and as a result any Python object can be referenced by PyObject*. The C API contains many of the functions that implement Python. In many cases there is a simple equivalence between Python functions and C functions. For example, the Python function dir(object) returns a list of names of the current locals for the specified object. The C API equivalent is pyObject_Dir(PyObject*) which returns a PyObject* pointer to a list of strings corresponding to the locals for the object referenced. The equivalence isn’t exact, but if you know your Python you know quite a lot of the C API. I suppose you could say, in the style of the zen of Python, in the C API everything is a PyObject. The Initialization FunctionAn extension module is just a shared library which exports an initialization function which has the signature: PyObject* PyInit_modulename(void) where modulename is the ASCII name of the module. If you want to use a Unicode module name you have to use a more complicated initialization called multi-phase initialization, see Chapter 11. When you import a module Python locates the file modulename.so under Linux or modulename.pyd under Windows and then tries to call PyInit_modulename. This also implies that PyInit_modulename is exported from the shared library, i.e. it can be called by an external program. You don’t have to do anything to export a function under Linux, but you do need to add __declspec(dllexport) for Windows. The solution is to simply use the PyMODINIT_FUNC macro which will automatically add the necessary __declspec(dllexport) under Windows. The pointer to PyObject returned should be a fully initialized module as returned by: PyObject* PyModule_Create(PyModuleDef* def) or PyObject *PyModule_Create2(PyModuleDef* def, The PyModuleDef struct has fields that determine how the module will be treated by the system: struct PyModuleDef { PyModuleDef_Base m_base; const char* m_name; const char* m_doc; Py_ssize_t m_size; PyMethodDef *m_methods; PyModuleDef_Slot *m_slots; traverseproc m_traverse; inquiry m_clear; freefunc m_free; }; Not all of the fields have to be used. The most important are:
The format of the PyMethodDef struct is: struct PyMethodDef { const char *ml_name; PyCFunction ml_meth; int ml_flags; const char *ml_doc; }; The fields are:
The ml_flags constant determines the calling convention for the function. For example, if it is set to METH_VARARGS then the function is passed two parameters. The first is a self which gives the instance if the function is called as a method and the module object if it is called as a function. The second is a tuple holding all of the parameters. Of course, both parameters are *PyObjects. The array of PyMethodDef structs is terminated by a sentinel value: {NULL, NULL, 0, NULL} To summarize:
|
||||
Last Updated ( Tuesday, 05 March 2024 ) |