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

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

#### Contents

Preface

1. Extending And Embedding Python
2. A First C Module Using Linux
3. A First C Module Using Windows
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
15. Embedding Python ***NEW!!!

<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);
}
{"myPi", Pi, METH_VARARGS, "Compute Pi"},
{NULL, NULL, 0, NULL} // sentinel
};
static struct PyModuleDef addmodule = {
"Pi",
"C library to compute Pi",
-1,
};
PyMODINIT_FUNC PyInit_Pi(void) {
}```

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}",
`"args": [                "-fdiagnostics-color=always",                "-g",                "-shared",                "\${file}",                "-o",                "Pi.so",                "-I/usr/local/include/python311"`