Skip to content

CPython

1. Essential Includes and Object Basics

Every C file interacting with the Python API must start with the Python header.

#include <Pythoh.h> 

PyObject* obj; 
// The fundamental structure; almost everything in the API is a pointer to a PyObject.

int Py_CheckReal(PyObject *o);
// Macros like PyLong_Check, PyList_Check, etc., verify the type of an object.

void Py_INCREF(PyObject *o);
// Increments the reference count of an object. Essential when keeping a reference.

void Py_DECREF(PyObject *o);
// Decrements the reference count. If it hits zero, the object is deallocated.

void Py_XINCREF(PyObject *o);
// Same as Py_INCREF, but safe to use if the pointer is NULL.

void Py_XDECREF(PyObject *o);
// Same as Py_DECREF, but safe to use if the pointer is NULL.

PyObject *Py_None;
/* The Python 'None' singleton. Always use Py_INCREF when returning this. */

PyObject *Py_True;
/* The Python 'True' singleton. */

PyObject *Py_False;
/* The Python 'False' singleton. */

int Py_Is(PyObject *x, PyObject *y);
/* Equivalent to 'x is y' in Python. Returns 1 if true, 0 otherwise. */

int Py_IsNone(PyObject *x);
/* Faster macro to check if an object is the None singleton. */

PyTypeObject *Py_TYPE(PyObject *o);
/* Macro that returns the type of the object 'o'. */

Py_ssize_t Py_SIZE(PyObject *o);
/* Macro that returns the size of a variable-sized object (like a list or string). */

PyObject* PyObject_Repr(PyObject *o);
/* Equivalent to repr(o). Returns a new reference to a string. */

PyObject* PyObject_Str(PyObject *o);
/* Equivalent to str(o). Returns a new reference to a string. */

int PyCallable_Check(PyObject *o);
/* Returns 1 if the object is a function, method, or class; 0 otherwise. */

PyObject* PyObject_Dir(PyObject *o);
/* Equivalent to dir(o). Returns a new list of strings. */

int PyObject_IsTrue(PyObject *o);
/* Equivalent to 'if o:' in Python. Returns 1 for truthy, 0 for falsy, -1 on error. */

int PyObject_Not(PyObject *o);
/* Equivalent to 'not o' in Python. Returns 1 if falsy, 0 if truthy. */

PyObject* PyObject_Type(PyObject *o);
/* Equivalent to type(o). Returns a new reference to the type object. */

int PyObject_HasAttrString(PyObject *o, const char *name);
/* Equivalent to hasattr(o, name). Returns 1 if it exists, 0 otherwise. */

Py_ssize_t PyObject_Length(PyObject *o);
/* Equivalent to len(o). Returns -1 on error. */

void Py_Initialize(void);
/* Initializes the Python interpreter. Used when embedding Python in C. */

int Py_FinalizeEx(void);
/* Shuts down the Python interpreter and frees its memory. */

2. Numeric Types (Longs and Floats)

Python 3 treats all integers as "Longs."

#include <Python.h>

PyObject* PyLong_FromLong(long v);
// Converts a C long to a Python integer object.

long PyLong_AsLong(PyObject *obj);
// Converts a Python integer back to a C long. Sets an error if type mismatch.

PyObject* PyFloat_FromDouble(double v);
// Converts a C double to a Python float object.

double PyFloat_AsDouble(PyObject *obj);
// Converts a Python float to a C double.

/* --- Integers (Longs) --- */

PyObject* PyLong_FromUnsignedLong(unsigned long v);
// Converts a C unsigned long to a Python integer.

PyObject* PyLong_FromLongLong(long long v);
// Converts a 64-bit C long long to a Python integer.

PyObject* PyLong_FromSize_t(size_t v);
// Converts a size_t (common for array indexing) to a Python integer.

long long PyLong_AsLongLong(PyObject *obj);
// Converts a Python integer to a C 64-bit long long.

unsigned long PyLong_AsUnsignedLong(PyObject *obj);
// Converts a Python integer to a C unsigned long; raises OverflowError if negative.

PyObject* PyLong_FromString(const char *str, char **pend, int base);
// Converts a C string to a Python integer based on the given base (e.g., 10, 16, or 0 to guess).

/* --- Numeric Properties and Checks --- */

int PyLong_Check(PyObject *p);
// Returns non-zero if 'p' is a Python integer or a subtype.

int PyLong_CheckExact(PyObject *p);
// Returns non-zero if 'p' is a Python integer, but NOT a subtype.

/* --- Integer Arithmetic (C-level) --- */

PyObject* PyNumber_Add(PyObject *o1, PyObject *o2);
// Equivalent to o1 + o2. Works for any numeric types. Returns a NEW reference.

PyObject* PyNumber_Subtract(PyObject *o1, PyObject *o2);
// Equivalent to o1 - o2. Returns a NEW reference.

PyObject* PyNumber_Multiply(PyObject *o1, PyObject *o2);
// Equivalent to o1 * o2. Returns a NEW reference.

PyObject* PyNumber_And(PyObject *o1, PyObject *o2);
// Equivalent to o1 & o2 (Bitwise AND). Returns a NEW reference.

/* --- Floats --- */

int PyFloat_Check(PyObject *p);
// Returns non-zero if 'p' is a Python float or a subtype.

PyObject* PyFloat_GetInfo(void);
// Returns a structseq containing information about the precision and range of floats.

double PyFloat_AS_DOUBLE(PyObject *obj);
// A faster MACRO version of PyFloat_AsDouble. No error checking (use only if PyFloat_Check is true).

/* --- Complex Numbers --- */

PyObject* PyComplex_FromDoubles(double real, double imag);
// Creates a Python complex number from two C doubles.

double PyComplex_RealAsDouble(PyObject *op);
// Returns the real part of a complex object as a C double.

double PyComplex_ImagAsDouble(PyObject *op);
// Returns the imaginary part of a complex object as a C double.

3. Strings and Unicode

Python strings are UTF-8 encoded internally but handled via Unicode objects in C.

PyObject* PyUnicode_FromString(const char *u);
// Creates a Python string from a NULL-terminated UTF-8 C string.

const char* PyUnicode_AsUTF8(PyObject *unicode);
// Returns a pointer to the UTF-8 representation of the Python string.

PyObject* PyUnicode_FromFormat(const char *format, ...);
// Similar to sprintf, but creates a Python Unicode object.
#include <Python.h>

/* --- Creation and Conversion --- */

PyObject* PyUnicode_FromStringAndSize(const char *u, Py_ssize_t size);
// Creates a Python string from a C string with a specific length (allows embedded NULLs).

PyObject* PyUnicode_FromEncodedObject(PyObject *obj, const char *encoding, const char *errors);
// Decodes a bytes-like object into a Unicode string using the specified encoding.

PyObject* PyUnicode_AsEncodedString(PyObject *unicode, const char *encoding, const char *errors);
// Encodes a Python Unicode object into a bytes object (e.g., "utf-8", "ascii"). Returns a NEW reference.

/* --- Specialized Encodings --- */

PyObject* PyUnicode_DecodeUTF8(const char *s, Py_ssize_t size, const char *errors);
// Explicitly decodes a UTF-8 C string of a given size into a Python string.

PyObject* PyUnicode_AsUTF8AndSize(PyObject *unicode, Py_ssize_t *size);
// Returns the UTF-8 buffer and stores its length in 'size'. More efficient than PyUnicode_AsUTF8.

/* --- Inspection and Checks --- */

int PyUnicode_Check(PyObject *o);
// Returns non-zero if 'o' is a Python Unicode object or a subtype.

int PyUnicode_CheckExact(PyObject *o);
// Returns non-zero if 'o' is exactly a Python Unicode object (not a subtype).

Py_ssize_t PyUnicode_GetLength(PyObject *unicode);
// Returns the number of characters (not bytes) in the Python string.

/* --- Modification and Search --- */

PyObject* PyUnicode_Concat(PyObject *left, PyObject *right);
// Equivalent to 'left + right' in Python. Returns a NEW reference.

Py_ssize_t PyUnicode_Find(PyObject *str, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction);
// Finds 'substr' in 'str'. Direction: 1 for forward, -1 for backward. Returns index or -1.

PyObject* PyUnicode_Replace(PyObject *str, PyObject *substr, PyObject *replstr, Py_ssize_t maxcount);
// Equivalent to 'str.replace(substr, replstr, maxcount)'. Returns a NEW reference.

PyObject* PyUnicode_Join(PyObject *separator, PyObject *seq);
// Equivalent to 'separator.join(seq)'. 'seq' should be an iterable of strings.

/* --- Advanced Formatting --- */

PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs);
// The 'va_list' version of PyUnicode_FromFormat, useful for wrapper functions.

/* --- Bytes Objects (The 'bytes' type) --- */

int PyBytes_Check(PyObject *o);
// Returns non-zero if 'o' is a bytes object.

PyObject* PyBytes_FromString(const char *v);
// Creates a Python bytes object from a NULL-terminated C string.

char* PyBytes_AsString(PyObject *o);
// Returns a pointer to the internal buffer of the bytes object.

4. Collections: Lists and Tuples

Lists are mutable; Tuples are immutable.

PyObject* PyList_New(Py_ssize_t len);
// Creates a new list of the specified length.

int PyList_SetItem(PyObject *list, Py_ssize_t index, PyObject *item);
// Sets an item at a specific index. Note: This "steals" a reference to 'item'.

PyObject* PyList_GetItem(PyObject *list, Py_ssize_t index);
// Returns the object at the index. Returns a "borrowed" reference.

PyObject* PyTuple_Pack(Py_ssize_t n, ...);
// Quick way to create a tuple from a sequence of PyObject pointers.
#include <Python.h>

/* --- List Operations (Mutable) --- */

int PyList_Append(PyObject *list, PyObject *item);
// Appends 'item' to the end of 'list'. Note: Does NOT steal a reference (increments refcount).

int PyList_Insert(PyObject *list, Py_ssize_t index, PyObject *item);
// Inserts 'item' at 'index'. Shifts subsequent items. Does NOT steal a reference.

Py_ssize_t PyList_Size(PyObject *list);
// Returns the number of items in the list. Returns -1 on error.

int PyList_Sort(PyObject *list);
// Sorts the list in place, similar to list.sort() in Python.

int PyList_Reverse(PyObject *list);
// Reverses the list in place, similar to list.reverse() in Python.

PyObject* PyList_AsTuple(PyObject *list);
// Creates a new tuple containing the same items as the list. Returns a NEW reference.

/* --- Tuple Operations (Immutable) --- */

PyObject* PyTuple_New(Py_ssize_t len);
// Creates a new tuple of a fixed size.

Py_ssize_t PyTuple_Size(PyObject *p);
// Returns the size of the tuple. Returns -1 on error.

PyObject* PyTuple_GetItem(PyObject *p, Py_ssize_t pos);
// Returns the object at 'pos'. Returns a BORROWED reference.

int PyTuple_SetItem(PyObject *p, Py_ssize_t pos, PyObject *o);
// Sets an item in a NEWLY CREATED tuple. Note: This STEALS a reference to 'o'. 
// (Only use this right after PyTuple_New before the tuple is shared).

PyObject* PyTuple_GetSlice(PyObject *p, Py_ssize_t low, Py_ssize_t high);
// Returns a slice of the tuple from 'low' to 'high'. Returns a NEW reference.

/* --- Generic Sequence Protocol --- */
/* These work on both Lists and Tuples (and any other sequence-like object) */

int PySequence_Check(PyObject *o);
// Returns 1 if the object provides the sequence protocol, 0 otherwise.

Py_ssize_t PySequence_Size(PyObject *o);
// Returns the length of any sequence (List, Tuple, String).

PyObject* PySequence_GetItem(PyObject *o, Py_ssize_t i);
// Returns the i-th element of a sequence. Returns a NEW reference (unlike PyList_GetItem).

PyObject* PySequence_Concat(PyObject *o1, PyObject *o2);
// Concatenates two sequences (like o1 + o2). Returns a NEW reference.

5. Dictionaries

PyObject* PyDict_New();
// Creates a new, empty dictionary.

int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val);
// Inserts a value using a C string as the key.

PyObject* PyDict_GetItemString(PyObject *p, const char *key);
// Retrieves a value using a C string key. Returns a borrowed reference.

6. Error Handling

The API uses a global thread-local state to track exceptions.

void PyErr_SetString(PyObject *type, const char *message);
// Sets the current exception (e.g., PyExc_TypeError) with a custom message.

PyObject* PyErr_Occurred();
// Checks if an exception is currently set. Returns the exception type or NULL.

void PyErr_Clear();
// Clears the current exception state.

7. Argument Parsing

This is the standard way to bridge Python arguments passed to a C function.

int PyArg_ParseTuple(PyObject *args, const char *format, ...);
// Parses positional arguments. "i" for int, "s" for string, "O" for PyObject.

int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *kw, const char *format, char *kwlist[], ...);
// Parses both positional and keyword arguments.

8. The Global Interpreter Lock (GIL)

Necessary when performing long-running C tasks or multi-threading.

/* --- GIL Management Macros --- */

Py_BEGIN_ALLOW_THREADS
/* Releases the GIL. Use this before long-running C code (I/O, heavy math) 
   so other Python threads can execute. Do NOT call any Python API functions inside this block. */

Py_END_ALLOW_THREADS
/* Re-acquires the GIL. Must be used to close a Py_BEGIN_ALLOW_THREADS block 
   before interacting with Python objects again. */

/* --- Explicit Thread State Management --- */

PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
/* Ensures the current thread has the GIL. Use this in C-created threads 
   (like callbacks from a library) that need to call Python functions. */

PyGILState_Release(gstate);
/* Releases the GIL and restores the previous thread state. 
   Must be paired with PyGILState_Ensure. */

/* --- Non-Blocking Checks --- */

int PyGILState_Check();
/* Returns 1 if the current thread holds the GIL, 0 otherwise. 
   Excellent for debugging or assertions in your C code. */

/* --- Advanced: Sub-interpreters --- */

PyThreadState* PyEval_SaveThread();
/* Releases the GIL and returns the current thread state. 
   Used for manual thread management. */

void PyEval_RestoreThread(PyThreadState *tstate);
/* Re-acquires the GIL and sets the thread state. */

/* --- Multi-phase Initialization (Python 3.7+) --- */

int Py_IsInitialized();
/* Returns true if the Python interpreter is currently running. */

9. Memory Management

1. Object Reference Counting

These macros manage the lifecycle of PyObject pointers. If an object's reference count hits zero, Python automatically deallocates it.

void Py_INCREF(PyObject *o);
// Increments the reference count. Essential when storing a pointer in a new location.

void Py_DECREF(PyObject *o);
// Decrements the reference count. Triggers deallocation if the count reaches zero.

void Py_XINCREF(PyObject *o);
// Safe version of Py_INCREF; does nothing if the pointer is NULL.

void Py_XDECREF(PyObject *o);
// Safe version of Py_DECREF; does nothing if the pointer is NULL.

void Py_CLEAR(PyObject *o);
// Sets the variable 'o' to NULL and then DECREFs the original object. Prevents double-frees.

Py_ssize_t Py_REFCNT(PyObject *o);
// Returns the current reference count (mostly for debugging/logging).

2. High-Level Object Allocation

Used when creating custom types or structures that Python's Garbage Collector (GC) needs to track.

PyObject* PyObject_New(type, typeobj);
// Allocates memory for a new Python object of a specific C-type and Python type object.

void PyObject_Del(void *op);
// Releases memory of an object previously allocated with PyObject_New.

PyObject* PyObject_Init(PyObject *op, PyTypeObject *type);
// Initializes the refcount and type pointer for a pre-allocated memory block.

int PyObject_GC_Track(PyObject *op);
// Tells the Python Garbage Collector to start tracking this object (for container types).

int PyObject_GC_UnTrack(PyObject *op);
// Stops the GC from tracking the object. Usually called right before freeing memory.

3. Raw Memory & Optimized Allocators

Python provides wrappers for malloc that integrate with its memory "arenas" for better performance and leak tracking.

void* PyMem_Malloc(size_t n);
// Python's wrapper for malloc(). Use for raw byte buffers and non-object memory.

void PyMem_Free(void *p);
// Frees memory allocated via the PyMem family.

void* PyObject_Malloc(size_t n);
// Specialized allocator optimized for small objects (< 512 bytes). Extremely fast.

void PyObject_Free(void *p);
// Frees memory allocated by PyObject_Malloc.

void* PyMem_Calloc(size_t nelem, size_t elsize);
// Allocates memory and initializes it to zeros (like C calloc).

10. Iteration and Collections

This section covers how to traverse Python’s core container types—Lists, Sets, and Dictionaries—using C. Note the differences in reference ownership (Borrowed vs. New) for each method.

1. List Iteration (Indexed)

The most common way to iterate through a list is using a standard C for loop.

Py_ssize_t size = PyList_Size(list);
for (Py_ssize_t i = 0; i < size; i++) {
    PyObject *item = PyList_GetItem(list, i); 
    // Returns a BORROWED reference. Do not DECREF unless you INCREF it.
}

2. Dictionary Iteration (Key-Value)

Dictionaries use a special internal position counter. Do not modify the dictionary during this loop.

Py_ssize_t pos = 0;
PyObject *key, *value;
while (PyDict_Next(dict, &pos, &key, &value)) {
    // Both 'key' and 'value' are BORROWED references.
    // 'pos' is updated automatically by the function.
}

3. Set Iteration

Sets do not support indexing, so you must use the Iterator Protocol or the internal entry traversal.

Py_ssize_t pos = 0;
PyObject *key;
Py_hash_t hash;
while (_PySet_NextEntry(set, &pos, &key, &hash)) {
    // 'key' is a BORROWED reference. 
    // Note: _PySet_NextEntry is technically internal but widely used for performance.
}

4. Generic Iterator Protocol (Universal)

Use this if you don't know the exact type but know it is iterable (works on Lists, Sets, Tuples, and Generators).

PyObject *iter = PyObject_GetIter(iterable);
// Returns a NEW reference to the iterator. Returns NULL on error.

if (iter) {
    PyObject *item;
    while ((item = PyIter_Next(iter))) {
        // 'item' is a NEW reference. You MUST DECREF it after use.
        Py_DECREF(item);
    }
    Py_DECREF(iter); // Always DECREF the iterator itself.
}

5. Truth Testing and Conditionals

Equivalent to the if and while logic in Python.

int PyObject_IsTrue(PyObject *o);
// Returns 1 if 'o' is true, 0 if false, -1 on error (equivalent to: if o:).

int PySequence_Contains(PyObject *seq, PyObject *item);
// Equivalent to 'item in seq'. Returns 1 if found, 0 if not, -1 on error.

In the C Python API, you cannot directly use a switch statement on a PyObject* because it is a pointer to a struct, not an integer or enum. Instead, you use truth-testing functions and rich comparisons to simulate if/else logic.

Here is the 11th section for your cheat sheet.


11. Conditionals and Comparisons

1. Emulating "switch case" (Type Checking)

Since you cannot switch on a PyObject, the common pattern is to check the object's type using an if/else if chain.

if (PyLong_Check(obj)) {
    // Case: Object is an int
} 
else if (PyUnicode_Check(obj)) {
    // Case: Object is a string
} 
else if (PyList_Check(obj)) {
    // Case: Object is a list
} 
else {
    // Default / else case
}

2. Emulating "switch case" (Value Checking)

If you are checking a Python string against multiple C strings, use strcmp with the UTF-8 representation.

const char *cmd = PyUnicode_AsUTF8(obj);

if (strcmp(cmd, "start") == 0) {
    // code for start
} else if (strcmp(cmd, "stop") == 0) {
    // code for stop
} else {
    // code for default
}

3. Type Comparison

Sometimes you want to check if two objects are exactly the same type.

if (Py_TYPE(obj1) == Py_TYPE(obj2)) {
    // True if both objects share the exact same Python class/type.
}

To expand the Input/Output section for the C Python API, it's important to differentiate between standard C I/O (which works but might bypass Python's buffer) and the API functions that interact directly with Python's sys.stdout or file objects.

Here is the expanded section for your cheat sheet.


12. Input and Output (I/O)

1. Printing to Python Streams

Using these ensures that your output respects Python redirections (like contextlib.redirect_stdout).

void PySys_WriteStdout(const char *format, ...);
// The C API equivalent of print(). Safe for formatted strings like printf.

void PySys_WriteStderr(const char *format, ...);
// Equivalent to sys.stderr.write(). Used for errors and warnings.

int PyFile_WriteObject(PyObject *obj, PyObject *f, int flags);
// Writes object 'obj' to file-like object 'f'. Flag Py_PRINT_RAW omits quotes.

2. Reading from Python Streams

How to get input from the user using Python’s internal mechanics.

PyObject* PySys_GetObject(const char *name);
// Gets a stream like "stdin", "stdout", or "stderr". Returns a BORROWED reference.

PyObject* PyObject_CallMethod(stream, "readline", NULL);
// Calls the .readline() method on a Python stream object. Returns a NEW reference.

3. File Descriptor & Path Handling

Bridging the gap between C's low-level file pointers and Python's high-level objects.

int PyObject_AsFileDescriptor(PyObject *p);
// Returns the C file descriptor (int) from a Python file object. Returns -1 on error.

PyObject* PyFile_FromFd(int fd, const char *name, const char *mode, ...);
// Creates a Python file object from a C file descriptor.

int PyUnicode_FSConverter(PyObject* obj, void* result);
// Converts a Python path (string/bytes) into a C-compatible bytes object for fopen().

4. Format Strings for I/O

When using functions like PySys_WriteStdout or PyUnicode_FromFormat, the API supports specific Python-only format characters:

Format Description
%p C pointer (void*)
%d C int
%zd Py_ssize_t (for sizes and indexes)
%S The str() representation of a PyObject*
%R The repr() representation of a PyObject*
%A The ascii() representation of a PyObject*

5. Interactive I/O

Used when building interactive shells or debuggers inside C.

PyObject* PyOS_Readline(FILE *stdin, FILE *stdout, const char *prompt);
// Displays a prompt and reads a line from the console using Python's logic.

int PyRun_SimpleString(const char *command);
// Executes a string as Python code. Useful for quick 'print' debugging.

13. Exception Handling and Interrupts

Error handling in the C API involves setting a global thread-local "exception indicator." When a function fails, it usually returns NULL or -1 and sets this indicator.

1. Raising Exceptions

Use these to signal an error from your C code to Python.

void PyErr_SetString(PyObject *type, const char *message);
// Raises an exception (e.g., PyExc_TypeError) with a custom string message.

void PyErr_SetObject(PyObject *type, PyObject *value);
// Raises an exception where the value is a specific Python object.

PyObject* PyErr_Format(PyObject *exception, const char *format, ...);
// Raises an exception using a printf-style format string. Returns NULL.

void PyErr_SetNone(PyObject *type);
// Raises an exception with no associated value/message.

2. Checking for Errors

Before proceeding, you often need to check if a previously called function failed.

PyObject* PyErr_Occurred();
// Returns the current exception type if one is set, otherwise NULL. Does not clear the error.

int PyErr_ExceptionMatches(PyObject *exc);
// Equivalent to 'except exc:'. Checks if the current error matches a specific type.

void PyErr_Clear();
// Clears the global exception indicator. Equivalent to a 'pass' in an except block.

PyObject* PyErr_NoMemory();
// Specialized shortcut to raise a MemoryError. Always returns NULL.

3. Catching and Handling (Try/Except)

To handle an error in C and continue execution, you must "fetch" the error state.

void PyErr_Fetch(PyObject **type, PyObject **value, PyObject **traceback);
// Retrieves the error and clears the indicator. You now own these NEW references.

void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback);
// Sets the error indicator using the three components. (Opposite of Fetch).

void PyErr_NormalizeException(PyObject **exc, PyObject **val, PyObject **tb);
// Ensures the fetched exception is a proper instance of the exception class.

4. Keyboard Interrupts (Ctrl+C)

In long-running C loops, Python cannot automatically catch a KeyboardInterrupt. You must manually poll for it.

int PyErr_CheckSignals();
// Polls the OS for signals (like SIGINT). Returns -1 if an interrupt occurred.

/* Usage Example in a Loop: */
for (int i = 0; i < 1000000; i++) {
    if (PyErr_CheckSignals() == -1) {
        return NULL; // Exit the C function and let Python handle the KeyboardInterrupt
    }
    // ... long processing ...
}

5. Common Exception Constants

These are the C-level names for standard Python exceptions:

Python Exception C API Constant
TypeError PyExc_TypeError
ValueError PyExc_ValueError
RuntimeError PyExc_RuntimeError
IndexError PyExc_IndexError
KeyError PyExc_KeyError
AttributeError PyExc_AttributeError