What is the purpose of Py_DECREF and PY_INCREF?
The CPython Garbage Collector uses 'Reference Counting', i.e it maintains a list of references to an object. If the reference count of an object falls to zero, it then implies that it is safe for the garbage collector to deallocate space for that object.
Hence, when we define PyObjects it is imperative that we explicitly call Py_INCREF and Py_DECREF, which increase and decrease reference counts of an object respectively.
In this case, Py_DECREF would simply free the memory allocated with tp->alloc.
tp->alloc sets the ref count to 1. Py_DECREF decreases the ref count from 1 to 0; as it finds the ref count is 0, it calls the appropriate functions to free the memory (Noddy_dealloc in this case.)
If a python C api function returns NULL, something has gone wrong; usually an exception is set (saved in a global variable).
If the caller returns NULL again, the exception is chained, hence the 'return NULL'.