Extending & Embedding Python Using C - Pi
Written by Mike James
Monday, 02 October 2023
Article Index
Extending & Embedding Python Using C - Pi
Using the module
Page 1 of 2

Discover what goes into coding a Python extension module and see how fast C is when compared to Python by using it to compute Pi.

Extending & Embedding Python Using C

By Mike James

extendPython360

Buy from Amazon.

Contents

Preface

  1. Extending And Embedding Python
  2. A First C Module Using Linux
  3. A First C Module Using Windows ***NEW!!!
  4. Module Basics
    Extract: A First Module
    Extract:
    Pi
  5. Arguments
  6. Returning Python Objects
  7. Objects And Attributes
  8. More Complex Objects – Tuples, Lists and Dicts
  9. Errors, Exceptions And Reference Counting
    Extract:
    Exceptions
  10. Bytes And Strings
  11. Modules And Attributes
  12. New Types
  13. Advanced Types
  14. Threads And The GIL
  15. Embedding Python

<ASIN:B0CK3X93KF>

In chapter but not in this extract

  • The API and PyObject
  • The Initialization Function
  • Initializing the arith Module

Computing Pi – How Fast?

As a second simple example, we can use a very simple computation to demonstrate the potential speed advantages that a C extension module offers. You can compute pi using the very simple series:

pi = 4*(1-1/3+1/5-1/7 ... )

This is very easy to implement, we just need to generate the odd integers, but to get pi to a reasonable number of digits you have to compute a lot of terms. In other words, this series is very slow to converge. The simple-minded approach is to write something like:

import time
def myPi(m,n):
 pi=0
 for k in range(m,n+1):
 s= 1 if k%2 else -1 
 pi += s / (2 * k - 1)
 return 4*pi

This computes the sum from m to n.

A main program to make use of this function is:

if __name__ == '__main__':
 N=10000000
 t1=time.perf_counter()
 pi=myPi(1,N)
 t2=time.perf_counter()
 print((t2-t1)*1000)
 print(pi)

If you try this out you will find that it gives pi to about five digits, which is not good for so many terms, but it is a good example to convert to a C extension.

The details of initializing the module follow the usual steps and the function is a fairly obvious translation of the Python:

#define PY_SSIZE_T_CLEAN
#include <Python.h>
static PyObject * Pi(PyObject *self, PyObject *args)
{
 int m, n;
 double pi,s;
 if (!PyArg_ParseTuple(args, "ii", &m, &n))
 return NULL;
 pi=0;
 for(int k=m;k<n;k++){
 s=1;
 if(k%2==0)s=-1;
 pi=pi+s/(2*k-1);
 } 
 return PyFloat_FromDouble(4*pi);
}
static PyMethodDef AddMethods[] = {
 {"myPi", Pi, METH_VARARGS, "Compute Pi"},
 {NULL, NULL, 0, NULL} // sentinel
};
static struct PyModuleDef addmodule = {
 PyModuleDef_HEAD_INIT,
 "Pi", 
 "C library to compute Pi", 
 -1, 
 AddMethods 
};
PyMODINIT_FUNC PyInit_Pi(void) { 
 return PyModule_Create(&addmodule);
}

The only real changes are to the names used for the module and function. Task.json also needs to be updated. The args for Windows is:

"args": [
 "/Zi",
 "/EHsc",
 "/nologo", 
 "/IC:/Users/user/AppData/Local/Programs
 /Python/Python311/include", 
 "${file}",
 "/link /dll /OUT:Pi.pyd 
 /LIBPATH:C:/Users/user/AppData/Local/
 Programs/Python/Python311/libs"

For Linux it is:

"args": [
"-fdiagnostics-color=always",
"-g",
"-shared",
"${file}",
"-o",
"Pi.so",
"-I/usr/local/include/python311"

With these changes the module should compile. If not go back to the instructions in chapters 2 and 3.

[画像:extendPython180]


Prev - Next >>

Last Updated ( Monday, 02 October 2023 )