3. Defining Extension Types: Assorted Topics¶
This section aims to give a quick fly-by on the various type methods you can implement and what they do.
Here is the definition of PyTypeObject
, with some fields only used in
debug builds omitted:
typedef struct _typeobject {
PyObject_VAR_HEAD
const char *tp_name; /* For printing, in format "<module>.<name>" */
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
/* Methods to implement standard operations */
destructor tp_dealloc;
Py_ssize_t tp_vectorcall_offset;
getattrfunc tp_getattr;
setattrfunc tp_setattr;
PyAsyncMethods *tp_as_async; /* formerly known as tp_compare (Python 2)
or tp_reserved (Python 3) */
reprfunc tp_repr;
/* Method suites for standard classes */
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
/* More standard operations (here for binary compatibility) */
hashfunc tp_hash;
ternaryfunc tp_call;
reprfunc tp_str;
getattrofunc tp_getattro;
setattrofunc tp_setattro;
/* Functions to access object as input/output buffer */
PyBufferProcs *tp_as_buffer;
/* Flags to define presence of optional/expanded features */
unsigned long tp_flags;
const char *tp_doc; /* Documentation string */
/* Assigned meaning in release 2.0 */
/* call function for all accessible objects */
traverseproc tp_traverse;
/* delete references to contained objects */
inquiry tp_clear;
/* Assigned meaning in release 2.1 */
/* rich comparisons */
richcmpfunc tp_richcompare;
/* weak reference enabler */
Py_ssize_t tp_weaklistoffset;
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
/* Attribute descriptor and subclassing stuff */
PyMethodDef *tp_methods;
PyMemberDef *tp_members;
PyGetSetDef *tp_getset;
// Strong reference on a heap type, borrowed reference on a static type
PyTypeObject *tp_base;
PyObject *tp_dict;
descrgetfunc tp_descr_get;
descrsetfunc tp_descr_set;
Py_ssize_t tp_dictoffset;
initproc tp_init;
allocfunc tp_alloc;
newfunc tp_new;
freefunc tp_free; /* Low-level free-memory routine */
inquiry tp_is_gc; /* For PyObject_IS_GC */
PyObject *tp_bases;
PyObject *tp_mro; /* method resolution order */
PyObject *tp_cache; /* no longer used */
void *tp_subclasses; /* for static builtin types this is an index */
PyObject *tp_weaklist; /* not used for static builtin types */
destructor tp_del;
/* Type attribute cache version tag. Added in version 2.6.
* If zero, the cache is invalid and must be initialized.
*/
unsigned int tp_version_tag;
destructor tp_finalize;
vectorcallfunc tp_vectorcall;
/* bitset of which type-watchers care about this type */
unsigned char tp_watched;
/* Number of tp_version_tag values used.
* Set to _Py_ATTR_CACHE_UNUSED if the attribute cache is
* disabled for this type (e.g. due to custom MRO entries).
* Otherwise, limited to MAX_VERSIONS_PER_CLASS (defined elsewhere).
*/
uint16_t tp_versions_used;
} PyTypeObject;
Now that’s a lot of methods. Don’t worry too much though – if you have a type you want to define, the chances are very good that you will only implement a handful of these.
As you probably expect by now, we’re going to go over this and give more information about the various handlers. We won’t go in the order they are defined in the structure, because there is a lot of historical baggage that impacts the ordering of the fields. It’s often easiest to find an example that includes the fields you need and then change the values to suit your new type.
const char *tp_name; /* For printing */
The name of the type – as mentioned in the previous chapter, this will appear in various places, almost entirely for diagnostic purposes. Try to choose something that will be helpful in such a situation!
Py_ssize_t tp_basicsize, tp_itemsize; /* For allocation */
These fields tell the runtime how much memory to allocate when new objects of
this type are created. Python has some built-in support for variable length
structures (think: strings, tuples) which is where the tp_itemsize
field
comes in. This will be dealt with later.
const char *tp_doc;
Here you can put a string (or its address) that you want returned when the
Python script references obj.__doc__
to retrieve the doc string.
Now we come to the basic type methods – the ones most extension types will implement.
3.1. Finalization and De-allocation¶
destructor tp_dealloc;
This function is called when the reference count of the instance of your type is reduced to zero and the Python interpreter wants to reclaim it. If your type has memory to free or other clean-up to perform, you can put it here. The object itself needs to be freed here as well. Here is an example of this function:
static void
newdatatype_dealloc(PyObject *op)
{
newdatatypeobject *self = (newdatatypeobject *) op;
free(self->obj_UnderlyingDatatypePtr);
Py_TYPE(self)->tp_free(self);
}
If your type supports garbage collection, the destructor should call
PyObject_GC_UnTrack()
before clearing any member fields:
static void
newdatatype_dealloc(PyObject *op)
{
newdatatypeobject *self = (newdatatypeobject *) op;
PyObject_GC_UnTrack(op);
Py_CLEAR(self->other_obj);
...
Py_TYPE(self)->tp_free(self);
}
One important requirement of the deallocator function is that it leaves any
pending exceptions alone. This is important since deallocators are frequently
called as the interpreter unwinds the Python stack; when the stack is unwound
due to an exception (rather than normal returns), nothing is done to protect the
deallocators from seeing that an exception has already been set. Any actions
which a deallocator performs which may cause additional Python code to be
executed may detect that an exception has been set. This can lead to misleading
errors from the interpreter. The proper way to protect against this is to save
a pending exception before performing the unsafe action, and restoring it when
done. This can be done using the PyErr_Fetch()
and
PyErr_Restore()
functions:
static void
my_dealloc(PyObject *obj)
{
MyObject *self = (MyObject *) obj;
PyObject *cbresult;
if (self->my_callback != NULL) {
PyObject *err_type, *err_value, *err_traceback;
/* This saves the current exception state */
PyErr_Fetch(&err_type, &err_value, &err_traceback);
cbresult = PyObject_CallNoArgs(self->my_callback);
if (cbresult == NULL) {
PyErr_WriteUnraisable(self->my_callback);
}
else {
Py_DECREF(cbresult);
}
/* This restores the saved exception state */
PyErr_Restore(err_type, err_value, err_traceback);
Py_DECREF(self->my_callback);
}
Py_TYPE(self)->tp_free(self);
}
Note
There are limitations to what you can safely do in a deallocator function.
First, if your type supports garbage collection (using tp_traverse
and/or tp_clear
), some of the object’s members can have been
cleared or finalized by the time tp_dealloc
is called. Second, in
tp_dealloc
, your object is in an unstable state: its reference
count is equal to zero. Any call to a non-trivial object or API (as in the
example above) might end up calling tp_dealloc
again, causing a
double free and a crash.
Starting with Python 3.4, it is recommended not to put any complex
finalization code in tp_dealloc
, and instead use the new
tp_finalize
type method.
See also
PEP 442 explains the new finalization scheme.
3.2. Object Presentation¶
In Python, there are two ways to generate a textual representation of an object:
the repr()
function, and the str()
function. (The print()
function just calls str()
.) These handlers are both optional.
reprfunc tp_repr;
reprfunc tp_str;
The tp_repr
handler should return a string object containing a
representation of the instance for which it is called. Here is a simple
example:
static PyObject *
newdatatype_repr(PyObject *op)
{
newdatatypeobject *self = (newdatatypeobject *) op;
return PyUnicode_FromFormat("Repr-ified_newdatatype{{size:%d}}",
self->obj_UnderlyingDatatypePtr->size);
}
If no tp_repr
handler is specified, the interpreter will supply a
representation that uses the type’s tp_name
and a uniquely identifying
value for the object.
The tp_str
handler is to str()
what the tp_repr
handler
described above is to repr()
; that is, it is called when Python code calls
str()
on an instance of your object. Its implementation is very similar
to the tp_repr
function, but the resulting string is intended for human
consumption. If tp_str
is not specified, the tp_repr
handler is
used instead.
Here is a simple example:
static PyObject *
newdatatype_str(PyObject *op)
{
newdatatypeobject *self = (newdatatypeobject *) op;
return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}",
self->obj_UnderlyingDatatypePtr->size);
}
3.3. Attribute Management¶
For every object which can support attributes, the corresponding type must
provide the functions that control how the attributes are resolved. There needs
to be a function which can retrieve attributes (if any are defined), and another
to set attributes (if setting attributes is allowed). Removing an attribute is
a special case, for which the new value passed to the handler is NULL
.
Python supports two pairs of attribute handlers; a type that supports attributes only needs to implement the functions for one pair. The difference is that one pair takes the name of the attribute as a char*, while the other accepts a PyObject*. Each type can use whichever pair makes more sense for the implementation’s convenience.
getattrfunc tp_getattr; /* char * version */
setattrfunc tp_setattr;
/* ... */
getattrofunc tp_getattro; /* PyObject * version */
setattrofunc tp_setattro;
If accessing attributes of an object is always a simple operation (this will be explained shortly), there are generic implementations which can be used to provide the PyObject* version of the attribute management functions. The actual need for type-specific attribute handlers almost completely disappeared starting with Python 2.2, though there are many examples which have not been updated to use some of the new generic mechanism that is available.
3.3.1. Generic Attribute Management¶
Most extension types only use simple attributes. So, what makes the attributes simple? There are only a couple of conditions that must be met:
The name of the attributes must be known when
PyType_Ready()
is called.No special processing is needed to record that an attribute was looked up or set, nor do actions need to be taken based on the value.
Note that this list does not place any restrictions on the values of the attributes, when the values are computed, or how relevant data is stored.
When PyType_Ready()
is called, it uses three tables referenced by the
type object to create descriptors which are placed in the dictionary of the
type object. Each descriptor controls access to one attribute of the instance
object. Each of the tables is optional; if all three are NULL
, instances of
the type will only have attributes that are inherited from their base type, and
should leave the tp_getattro
and tp_setattro
fields NULL
as
well, allowing the base type to handle attributes.
The tables are declared as three fields of the type object:
struct PyMethodDef *tp_methods;
struct PyMemberDef *tp_members;
struct PyGetSetDef *tp_getset;
If tp_methods
is not NULL
, it must refer to an array of
PyMethodDef
structures. Each entry in the table is an instance of this
structure:
typedef struct PyMethodDef {
const char *ml_name; /* method name */
PyCFunction ml_meth; /* implementation function */
int ml_flags; /* flags */
const char *ml_doc; /* docstring */
} PyMethodDef;
One entry should be defined for each method provided by the type; no entries are
needed for methods inherited from a base type. One additional entry is needed
at the end; it is a sentinel that marks the end of the array. The
ml_name
field of the sentinel must be NULL
.
The second table is used to define attributes which map directly to data stored in the instance. A variety of primitive C types are supported, and access may be read-only or read-write. The structures in the table are defined as:
typedef struct PyMemberDef {
const char *name;
int type;
int offset;
int flags;
const char *doc;
} PyMemberDef;
For each entry in the table, a descriptor will be constructed and added to the
type which will be able to extract a value from the instance structure. The
type
field should contain a type code like Py_T_INT
or
Py_T_DOUBLE
; the value will be used to determine how to
convert Python values to and from C values. The flags
field is used to
store flags which control how the attribute can be accessed: you can set it to
Py_READONLY
to prevent Python code from setting it.
An interesting advantage of using the tp_members
table to build
descriptors that are used at runtime is that any attribute defined this way can
have an associated doc string simply by providing the text in the table. An
application can use the introspection API to retrieve the descriptor from the
class object, and get the doc string using its __doc__
attribute.
As with the tp_methods
table, a sentinel entry with a ml_name
value
of NULL
is required.
3.3.2. Type-specific Attribute Management¶
For simplicity, only the char* version will be demonstrated here; the type of the name parameter is the only difference between the char* and PyObject* flavors of the interface. This example effectively does the same thing as the generic example above, but does not use the generic support added in Python 2.2. It explains how the handler functions are called, so that if you do need to extend their functionality, you’ll understand what needs to be done.
The tp_getattr
handler is called when the object requires an attribute
look-up. It is called in the same situations where the __getattr__()
method of a class would be called.
Here is an example:
static PyObject *
newdatatype_getattr(PyObject *op, char *name)
{
newdatatypeobject *self = (newdatatypeobject *) op;
if (strcmp(name, "data") == 0) {
return PyLong_FromLong(self->data);
}
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%.400s'",
Py_TYPE(self)->tp_name, name);
return NULL;
}
The tp_setattr
handler is called when the __setattr__()
or
__delattr__()
method of a class instance would be called. When an
attribute should be deleted, the third parameter will be NULL
. Here is an
example that simply raises an exception; if this were really all you wanted, the
tp_setattr
handler should be set to NULL
.
static int
newdatatype_setattr(PyObject *op, char *name, PyObject *v)
{
PyErr_Format(PyExc_RuntimeError, "Read-only attribute: %s", name);
return -1;
}
3.4. Object Comparison¶
richcmpfunc tp_richcompare;
The tp_richcompare
handler is called when comparisons are needed. It is
analogous to the rich comparison methods, like
__lt__()
, and also called by PyObject_RichCompare()
and
PyObject_RichCompareBool()
.
This function is called with two Python objects and the operator as arguments,
where the operator is one of Py_EQ
, Py_NE
, Py_LE
, Py_GE
,
Py_LT
or Py_GT
. It should compare the two objects with respect to the
specified operator and return Py_True
or Py_False
if the comparison is
successful, Py_NotImplemented
to indicate that comparison is not
implemented and the other object’s comparison method should be tried, or NULL
if an exception was set.
Here is a sample implementation, for a datatype that is considered equal if the size of an internal pointer is equal:
static PyObject *
newdatatype_richcmp(PyObject *lhs, PyObject *rhs, int op)
{
newdatatypeobject *obj1 = (newdatatypeobject *) lhs;
newdatatypeobject *obj2 = (newdatatypeobject *) rhs;
PyObject *result;
int c, size1, size2;
/* code to make sure that both arguments are of type
newdatatype omitted */
size1 = obj1->obj_UnderlyingDatatypePtr->size;
size2 = obj2->obj_UnderlyingDatatypePtr->size;
switch (op) {
case Py_LT: c = size1 < size2; break;
case Py_LE: c = size1 <= size2; break;
case Py_EQ: c = size1 == size2; break;
case Py_NE: c = size1 != size2; break;
case Py_GT: c = size1 > size2; break;
case Py_GE: c = size1 >= size2; break;
}
result = c ? Py_True : Py_False;
return Py_NewRef(result);
}
3.5. Abstract Protocol Support¶
Python supports a variety of abstract ‘protocols;’ the specific interfaces provided to use these interfaces are documented in Abstract Objects Layer.
A number of these abstract interfaces were defined early in the development of
the Python implementation. In particular, the number, mapping, and sequence
protocols have been part of Python since the beginning. Other protocols have
been added over time. For protocols which depend on several handler routines
from the type implementation, the older protocols have been defined as optional
blocks of handlers referenced by the type object. For newer protocols there are
additional slots in the main type object, with a flag bit being set to indicate
that the slots are present and should be checked by the interpreter. (The flag
bit does not indicate that the slot values are non-NULL
. The flag may be set
to indicate the presence of a slot, but a slot may still be unfilled.)
PyNumberMethods *tp_as_number;
PySequenceMethods *tp_as_sequence;
PyMappingMethods *tp_as_mapping;
If you wish your object to be able to act like a number, a sequence, or a
mapping object, then you place the address of a structure that implements the C
type PyNumberMethods
, PySequenceMethods
, or
PyMappingMethods
, respectively. It is up to you to fill in this
structure with appropriate values. You can find examples of the use of each of
these in the Objects
directory of the Python source distribution.
hashfunc tp_hash;
This function, if you choose to provide it, should return a hash number for an instance of your data type. Here is a simple example:
static Py_hash_t
newdatatype_hash(PyObject *op)
{
newdatatypeobject *self = (newdatatypeobject *) op;
Py_hash_t result;
result = self->some_size + 32767 * self->some_number;
if (result == -1) {
result = -2;
}
return result;
}
Py_hash_t
is a signed integer type with a platform-varying width.
Returning -1
from tp_hash
indicates an error,
which is why you should be careful to avoid returning it when hash computation
is successful, as seen above.
ternaryfunc tp_call;
This function is called when an instance of your data type is “called”, for
example, if obj1
is an instance of your data type and the Python script
contains obj1('hello')
, the tp_call
handler is invoked.
This function takes three arguments:
self is the instance of the data type which is the subject of the call. If the call is
obj1('hello')
, then self isobj1
.args is a tuple containing the arguments to the call. You can use
PyArg_ParseTuple()
to extract the arguments.kwds is a dictionary of keyword arguments that were passed. If this is non-
NULL
and you support keyword arguments, usePyArg_ParseTupleAndKeywords()
to extract the arguments. If you do not want to support keyword arguments and this is non-NULL
, raise aTypeError
with a message saying that keyword arguments are not supported.
Here is a toy tp_call
implementation:
static PyObject *
newdatatype_call(PyObject *op, PyObject *args, PyObject *kwds)
{
newdatatypeobject *self = (newdatatypeobject *) op;
PyObject *result;
const char *arg1;
const char *arg2;
const char *arg3;
if (!PyArg_ParseTuple(args, "sss:call", &arg1, &arg2, &arg3)) {
return NULL;
}
result = PyUnicode_FromFormat(
"Returning -- value: [%d] arg1: [%s] arg2: [%s] arg3: [%s]\n",
self->obj_UnderlyingDatatypePtr->size,
arg1, arg2, arg3);
return result;
}
/* Iterators */
getiterfunc tp_iter;
iternextfunc tp_iternext;
These functions provide support for the iterator protocol. Both handlers
take exactly one parameter, the instance for which they are being called,
and return a new reference. In the case of an error, they should set an
exception and return NULL
. tp_iter
corresponds
to the Python __iter__()
method, while tp_iternext
corresponds to the Python __next__()
method.
Any iterable object must implement the tp_iter
handler, which must return an iterator object. Here the same guidelines
apply as for Python classes:
For collections (such as lists and tuples) which can support multiple independent iterators, a new iterator should be created and returned by each call to
tp_iter
.Objects which can only be iterated over once (usually due to side effects of iteration, such as file objects) can implement
tp_iter
by returning a new reference to themselves – and should also therefore implement thetp_iternext
handler.
Any iterator object should implement both tp_iter
and tp_iternext
. An iterator’s
tp_iter
handler should return a new reference
to the iterator. Its tp_iternext
handler should
return a new reference to the next object in the iteration, if there is one.
If the iteration has reached the end, tp_iternext
may return NULL
without setting an exception, or it may set
StopIteration
in addition to returning NULL
; avoiding
the exception can yield slightly better performance. If an actual error
occurs, tp_iternext
should always set an exception
and return NULL
.
3.6. Weak Reference Support¶
One of the goals of Python’s weak reference implementation is to allow any type to participate in the weak reference mechanism without incurring the overhead on performance-critical objects (such as numbers).
See also
Documentation for the weakref
module.
For an object to be weakly referenceable, the extension type must set the
Py_TPFLAGS_MANAGED_WEAKREF
bit of the tp_flags
field. The legacy tp_weaklistoffset
field should
be left as zero.
Concretely, here is how the statically declared type object would look:
static PyTypeObject TrivialType = {
PyVarObject_HEAD_INIT(NULL, 0)
/* ... other members omitted for brevity ... */
.tp_flags = Py_TPFLAGS_MANAGED_WEAKREF | ...,
};
The only further addition is that tp_dealloc
needs to clear any weak
references (by calling PyObject_ClearWeakRefs()
):
static void
Trivial_dealloc(PyObject *op)
{
/* Clear weakrefs first before calling any destructors */
PyObject_ClearWeakRefs(op);
/* ... remainder of destruction code omitted for brevity ... */
Py_TYPE(op)->tp_free(op);
}
3.7. More Suggestions¶
In order to learn how to implement any specific method for your new data type,
get the CPython source code. Go to the Objects
directory,
then search the C source files for tp_
plus the function you want
(for example, tp_richcompare
). You will find examples of the function
you want to implement.
When you need to verify that an object is a concrete instance of the type you
are implementing, use the PyObject_TypeCheck()
function. A sample of
its use might be something like the following:
if (!PyObject_TypeCheck(some_object, &MyType)) {
PyErr_SetString(PyExc_TypeError, "arg #1 not a mything");
return NULL;
}
See also
- Download CPython source releases.
- The CPython project on GitHub, where the CPython source code is developed.


Defining Extension Types: Tutorial

2. Defining Extension Types: Tutorial¶
Python allows the writer of a C extension module to define new types that
can be manipulated from Python code, much like the built-in str
and list
types. The code for all extension types follows a
pattern, but there are some details that you need to understand before you
can get started. This document is a gentle introduction to the topic.
2.1. The Basics¶
The CPython runtime sees all Python objects as variables of type
PyObject*, which serves as a “base type” for all Python objects.
The PyObject
structure itself only contains the object’s
reference count and a pointer to the object’s “type object”.
This is where the action is; the type object determines which (C) functions
get called by the interpreter when, for instance, an attribute gets looked up
on an object, a method called, or it is multiplied by another object. These
C functions are called “type methods”.
So, if you want to define a new extension type, you need to create a new type object.
This sort of thing can only be explained by example, so here’s a minimal, but
complete, module that defines a new type named Custom
inside a C
extension module custom
:
Note
What we’re showing here is the traditional way of defining static
extension types. It should be adequate for most uses. The C API also
allows defining heap-allocated extension types using the
PyType_FromSpec()
function, which isn’t covered in this tutorial.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
} CustomObject;
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = PyType_GenericNew,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
// Just use this while using static types
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom(void)
{
return PyModuleDef_Init(&custom_module);
}
Now that’s quite a bit to take in at once, but hopefully bits will seem familiar from the previous chapter. This file defines three things:
What a
Custom
object contains: this is theCustomObject
struct, which is allocated once for eachCustom
instance.How the
Custom
type behaves: this is theCustomType
struct, which defines a set of flags and function pointers that the interpreter inspects when specific operations are requested.How to define and execute the
custom
module: this is thePyInit_custom
function and the associatedcustom_module
struct for defining the module, and thecustom_module_exec
function to set up a fresh module object.
The first bit is:
typedef struct {
PyObject_HEAD
} CustomObject;
This is what a Custom object will contain. PyObject_HEAD
is mandatory
at the start of each object struct and defines a field called ob_base
of type PyObject
, containing a pointer to a type object and a
reference count (these can be accessed using the macros Py_TYPE
and Py_REFCNT
respectively). The reason for the macro is to
abstract away the layout and to enable additional fields in debug builds.
Note
There is no semicolon above after the PyObject_HEAD
macro.
Be wary of adding one by accident: some compilers will complain.
Of course, objects generally store additional data besides the standard
PyObject_HEAD
boilerplate; for example, here is the definition for
standard Python floats:
typedef struct {
PyObject_HEAD
double ob_fval;
} PyFloatObject;
The second bit is the definition of the type object.
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = PyType_GenericNew,
};
Note
We recommend using C99-style designated initializers as above, to
avoid listing all the PyTypeObject
fields that you don’t care
about and also to avoid caring about the fields’ declaration order.
The actual definition of PyTypeObject
in object.h
has
many more fields than the definition above. The
remaining fields will be filled with zeros by the C compiler, and it’s
common practice to not specify them explicitly unless you need them.
We’re going to pick it apart, one field at a time:
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
This line is mandatory boilerplate to initialize the ob_base
field mentioned above.
.tp_name = "custom.Custom",
The name of our type. This will appear in the default textual representation of our objects and in some error messages, for example:
>>> "" + custom.Custom()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "custom.Custom") to str
Note that the name is a dotted name that includes both the module name and the
name of the type within the module. The module in this case is custom
and
the type is Custom
, so we set the type name to custom.Custom
.
Using the real dotted import path is important to make your type compatible
with the pydoc
and pickle
modules.
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
This is so that Python knows how much memory to allocate when creating
new Custom
instances. tp_itemsize
is
only used for variable-sized objects and should otherwise be zero.
Note
If you want your type to be subclassable from Python, and your type has the same
tp_basicsize
as its base type, you may have problems with multiple
inheritance. A Python subclass of your type will have to list your type first
in its __bases__
, or else it will not be able to call your type’s
__new__()
method without getting an error. You can avoid this problem by
ensuring that your type has a larger value for tp_basicsize
than its
base type does. Most of the time, this will be true anyway, because either your
base type will be object
, or else you will be adding data members to
your base type, and therefore increasing its size.
We set the class flags to Py_TPFLAGS_DEFAULT
.
.tp_flags = Py_TPFLAGS_DEFAULT,
All types should include this constant in their flags. It enables all of the members defined until at least Python 3.3. If you need further members, you will need to OR the corresponding flags.
We provide a doc string for the type in tp_doc
.
.tp_doc = PyDoc_STR("Custom objects"),
To enable object creation, we have to provide a tp_new
handler. This is the equivalent of the Python method __new__()
, but
has to be specified explicitly. In this case, we can just use the default
implementation provided by the API function PyType_GenericNew()
.
.tp_new = PyType_GenericNew,
Everything else in the file should be familiar, except for some code in
custom_module_exec()
:
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
This initializes the Custom
type, filling in a number of members
to the appropriate default values, including ob_type
that we initially
set to NULL
.
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
This adds the type to the module dictionary. This allows us to create
Custom
instances by calling the Custom
class:
>>> import custom
>>> mycustom = custom.Custom()
That’s it! All that remains is to build it; put the above code in a file called
custom.c
,
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "custom"
version = "1"
in a file called pyproject.toml
, and
from setuptools import Extension, setup
setup(ext_modules=[Extension("custom", ["custom.c"])])
in a file called setup.py
; then typing
$ python -m pip install .
in a shell should produce a file custom.so
in a subdirectory
and install it; now fire up Python — you should be able to import custom
and play around with Custom
objects.
That wasn’t so hard, was it?
Of course, the current Custom type is pretty uninteresting. It has no data and doesn’t do anything. It can’t even be subclassed.
2.2. Adding data and methods to the Basic example¶
Let’s extend the basic example to add some data and methods. Let’s also make
the type usable as a base class. We’ll create a new module, custom2
that
adds these capabilities:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static void
Custom_dealloc(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free(self);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
Py_XSETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_XSETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyMemberDef Custom_members[] = {
{"first", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,
"first name"},
{"last", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,
"last name"},
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom2.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_new = Custom_new,
.tp_init = Custom_init,
.tp_dealloc = Custom_dealloc,
.tp_members = Custom_members,
.tp_methods = Custom_methods,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom2",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom2(void)
{
return PyModuleDef_Init(&custom_module);
}
This version of the module has a number of changes.
The Custom
type now has three data attributes in its C struct,
first, last, and number. The first and last variables are Python
strings containing first and last names. The number attribute is a C integer.
The object structure is updated accordingly:
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
Because we now have data to manage, we have to be more careful about object allocation and deallocation. At a minimum, we need a deallocation method:
static void
Custom_dealloc(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free(self);
}
which is assigned to the tp_dealloc
member:
.tp_dealloc = Custom_dealloc,
This method first clears the reference counts of the two Python attributes.
Py_XDECREF()
correctly handles the case where its argument is
NULL
(which might happen here if tp_new
failed midway). It then
calls the tp_free
member of the object’s type
(computed by Py_TYPE(self)
) to free the object’s memory. Note that
the object’s type might not be CustomType
, because the object may
be an instance of a subclass.
Note
The explicit cast to CustomObject *
above is needed because we defined
Custom_dealloc
to take a PyObject *
argument, as the tp_dealloc
function pointer expects to receive a PyObject *
argument.
By assigning to the tp_dealloc
slot of a type, we declare
that it can only be called with instances of our CustomObject
class, so the cast to (CustomObject *)
is safe.
This is object-oriented polymorphism, in C!
In existing code, or in previous versions of this tutorial,
you might see similar functions take a pointer to the subtype
object structure (CustomObject*
) directly, like this:
Custom_dealloc(CustomObject *self)
{
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject *) self);
}
...
.tp_dealloc = (destructor) Custom_dealloc,
This does the same thing on all architectures that CPython supports, but according to the C standard, it invokes undefined behavior.
We want to make sure that the first and last names are initialized to empty
strings, so we provide a tp_new
implementation:
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = PyUnicode_FromString("");
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = PyUnicode_FromString("");
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
and install it in the tp_new
member:
.tp_new = Custom_new,
The tp_new
handler is responsible for creating (as opposed to initializing)
objects of the type. It is exposed in Python as the __new__()
method.
It is not required to define a tp_new
member, and indeed many extension
types will simply reuse PyType_GenericNew()
as done in the first
version of the Custom
type above. In this case, we use the tp_new
handler to initialize the first
and last
attributes to non-NULL
default values.
tp_new
is passed the type being instantiated (not necessarily CustomType
,
if a subclass is instantiated) and any arguments passed when the type was
called, and is expected to return the instance created. tp_new
handlers
always accept positional and keyword arguments, but they often ignore the
arguments, leaving the argument handling to initializer (a.k.a. tp_init
in C or __init__
in Python) methods.
Note
tp_new
shouldn’t call tp_init
explicitly, as the interpreter
will do it itself.
The tp_new
implementation calls the tp_alloc
slot to allocate memory:
self = (CustomObject *) type->tp_alloc(type, 0);
Since memory allocation may fail, we must check the tp_alloc
result against NULL
before proceeding.
Note
We didn’t fill the tp_alloc
slot ourselves. Rather
PyType_Ready()
fills it for us by inheriting it from our base class,
which is object
by default. Most types use the default allocation
strategy.
Note
If you are creating a co-operative tp_new
(one
that calls a base type’s tp_new
or __new__()
),
you must not try to determine what method to call using method resolution
order at runtime. Always statically determine what type you are going to
call, and call its tp_new
directly, or via
type->tp_base->tp_new
. If you do not do this, Python subclasses of your
type that also inherit from other Python-defined classes may not work correctly.
(Specifically, you may not be able to create instances of such subclasses
without getting a TypeError
.)
We also define an initialization function which accepts arguments to provide initial values for our instance:
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_XDECREF(tmp);
}
return 0;
}
by filling the tp_init
slot.
.tp_init = Custom_init,
The tp_init
slot is exposed in Python as the
__init__()
method. It is used to initialize an object after it’s
created. Initializers always accept positional and keyword arguments,
and they should return either 0
on success or -1
on error.
Unlike the tp_new
handler, there is no guarantee that tp_init
is called at all (for example, the pickle
module by default
doesn’t call __init__()
on unpickled instances). It can also be
called multiple times. Anyone can call the __init__()
method on
our objects. For this reason, we have to be extra careful when assigning
the new attribute values. We might be tempted, for example to assign the
first
member like this:
if (first) {
Py_XDECREF(self->first);
Py_INCREF(first);
self->first = first;
}
But this would be risky. Our type doesn’t restrict the type of the
first
member, so it could be any kind of object. It could have a
destructor that causes code to be executed that tries to access the
first
member; or that destructor could detach the
thread state and let arbitrary code run in other
threads that accesses and modifies our object.
To be paranoid and protect ourselves against this possibility, we almost always reassign members before decrementing their reference counts. When don’t we have to do this?
when we absolutely know that the reference count is greater than 1;
when we know that deallocation of the object [1] will neither detach the thread state nor cause any calls back into our type’s code;
when decrementing a reference count in a
tp_dealloc
handler on a type which doesn’t support cyclic garbage collection [2].
We want to expose our instance variables as attributes. There are a number of ways to do that. The simplest way is to define member definitions:
static PyMemberDef Custom_members[] = {
{"first", Py_T_OBJECT_EX, offsetof(CustomObject, first), 0,
"first name"},
{"last", Py_T_OBJECT_EX, offsetof(CustomObject, last), 0,
"last name"},
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
and put the definitions in the tp_members
slot:
.tp_members = Custom_members,
Each member definition has a member name, type, offset, access flags and documentation string. See the Generic Attribute Management section below for details.
A disadvantage of this approach is that it doesn’t provide a way to restrict the
types of objects that can be assigned to the Python attributes. We expect the
first and last names to be strings, but any Python objects can be assigned.
Further, the attributes can be deleted, setting the C pointers to NULL
. Even
though we can make sure the members are initialized to non-NULL
values, the
members can be set to NULL
if the attributes are deleted.
We define a single method, Custom.name()
, that outputs the objects name as the
concatenation of the first and last names.
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
The method is implemented as a C function that takes a Custom
(or
Custom
subclass) instance as the first argument. Methods always take an
instance as the first argument. Methods often take positional and keyword
arguments as well, but in this case we don’t take any and don’t need to accept
a positional argument tuple or keyword argument dictionary. This method is
equivalent to the Python method:
def name(self):
return "%s %s" % (self.first, self.last)
Note that we have to check for the possibility that our first
and
last
members are NULL
. This is because they can be deleted, in which
case they are set to NULL
. It would be better to prevent deletion of these
attributes and to restrict the attribute values to be strings. We’ll see how to
do that in the next section.
Now that we’ve defined the method, we need to create an array of method definitions:
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
(note that we used the METH_NOARGS
flag to indicate that the method
is expecting no arguments other than self)
and assign it to the tp_methods
slot:
.tp_methods = Custom_methods,
Finally, we’ll make our type usable as a base class for subclassing. We’ve
written our methods carefully so far so that they don’t make any assumptions
about the type of the object being created or used, so all we need to do is
to add the Py_TPFLAGS_BASETYPE
to our class flag definition:
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
We rename PyInit_custom()
to PyInit_custom2()
, update the
module name in the PyModuleDef
struct, and update the full class
name in the PyTypeObject
struct.
Finally, we update our setup.py
file to include the new module,
from setuptools import Extension, setup
setup(ext_modules=[
Extension("custom", ["custom.c"]),
Extension("custom2", ["custom2.c"]),
])
and then we re-install so that we can import custom2
:
$ python -m pip install .
2.3. Providing finer control over data attributes¶
In this section, we’ll provide finer control over how the first
and
last
attributes are set in the Custom
example. In the previous
version of our module, the instance variables first
and last
could be set to non-string values or even deleted. We want to make sure that
these attributes always contain strings.
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static void
Custom_dealloc(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_XDECREF(self->first);
Py_XDECREF(self->last);
Py_TYPE(self)->tp_free(self);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
Py_SETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_SETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyMemberDef Custom_members[] = {
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
static PyObject *
Custom_getfirst(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->first);
}
static int
Custom_setfirst(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
Py_SETREF(self->first, Py_NewRef(value));
return 0;
}
static PyObject *
Custom_getlast(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->last);
}
static int
Custom_setlast(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The last attribute value must be a string");
return -1;
}
Py_SETREF(self->last, Py_NewRef(value));
return 0;
}
static PyGetSetDef Custom_getsetters[] = {
{"first", Custom_getfirst, Custom_setfirst,
"first name", NULL},
{"last", Custom_getlast, Custom_setlast,
"last name", NULL},
{NULL} /* Sentinel */
};
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom3.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_new = Custom_new,
.tp_init = Custom_init,
.tp_dealloc = Custom_dealloc,
.tp_members = Custom_members,
.tp_methods = Custom_methods,
.tp_getset = Custom_getsetters,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom3",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom3(void)
{
return PyModuleDef_Init(&custom_module);
}
To provide greater control, over the first
and last
attributes,
we’ll use custom getter and setter functions. Here are the functions for
getting and setting the first
attribute:
static PyObject *
Custom_getfirst(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
Py_INCREF(self->first);
return self->first;
}
static int
Custom_setfirst(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
PyObject *tmp;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
tmp = self->first;
Py_INCREF(value);
self->first = value;
Py_DECREF(tmp);
return 0;
}
The getter function is passed a Custom
object and a “closure”, which is
a void pointer. In this case, the closure is ignored. (The closure supports an
advanced usage in which definition data is passed to the getter and setter. This
could, for example, be used to allow a single set of getter and setter functions
that decide the attribute to get or set based on data in the closure.)
The setter function is passed the Custom
object, the new value, and the
closure. The new value may be NULL
, in which case the attribute is being
deleted. In our setter, we raise an error if the attribute is deleted or if its
new value is not a string.
We create an array of PyGetSetDef
structures:
static PyGetSetDef Custom_getsetters[] = {
{"first", Custom_getfirst, Custom_setfirst,
"first name", NULL},
{"last", Custom_getlast, Custom_setlast,
"last name", NULL},
{NULL} /* Sentinel */
};
and register it in the tp_getset
slot:
.tp_getset = Custom_getsetters,
The last item in a PyGetSetDef
structure is the “closure” mentioned
above. In this case, we aren’t using a closure, so we just pass NULL
.
We also remove the member definitions for these attributes:
static PyMemberDef Custom_members[] = {
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
We also need to update the tp_init
handler to only
allow strings [3] to be passed:
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_DECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_DECREF(tmp);
}
return 0;
}
With these changes, we can assure that the first
and last
members are
never NULL
so we can remove checks for NULL
values in almost all cases.
This means that most of the Py_XDECREF()
calls can be converted to
Py_DECREF()
calls. The only place we can’t change these calls is in
the tp_dealloc
implementation, where there is the possibility that the
initialization of these members failed in tp_new
.
We also rename the module initialization function and module name in the
initialization function, as we did before, and we add an extra definition to the
setup.py
file.
2.4. Supporting cyclic garbage collection¶
Python has a cyclic garbage collector (GC) that can identify unneeded objects even when their reference counts are not zero. This can happen when objects are involved in cycles. For example, consider:
>>> l = []
>>> l.append(l)
>>> del l
In this example, we create a list that contains itself. When we delete it, it still has a reference from itself. Its reference count doesn’t drop to zero. Fortunately, Python’s cyclic garbage collector will eventually figure out that the list is garbage and free it.
In the second version of the Custom
example, we allowed any kind of
object to be stored in the first
or last
attributes [4].
Besides, in the second and third versions, we allowed subclassing
Custom
, and subclasses may add arbitrary attributes. For any of
those two reasons, Custom
objects can participate in cycles:
>>> import custom3
>>> class Derived(custom3.Custom): pass
...
>>> n = Derived()
>>> n.some_attribute = n
To allow a Custom
instance participating in a reference cycle to
be properly detected and collected by the cyclic GC, our Custom
type
needs to fill two additional slots and to enable a flag that enables these slots:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include <stddef.h> /* for offsetof() */
typedef struct {
PyObject_HEAD
PyObject *first; /* first name */
PyObject *last; /* last name */
int number;
} CustomObject;
static int
Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
CustomObject *self = (CustomObject *) op;
Py_VISIT(self->first);
Py_VISIT(self->last);
return 0;
}
static int
Custom_clear(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_CLEAR(self->first);
Py_CLEAR(self->last);
return 0;
}
static void
Custom_dealloc(PyObject *op)
{
PyObject_GC_UnTrack(op);
(void)Custom_clear(op);
Py_TYPE(op)->tp_free(op);
}
static PyObject *
Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
if (self != NULL) {
self->first = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->first == NULL) {
Py_DECREF(self);
return NULL;
}
self->last = Py_GetConstant(Py_CONSTANT_EMPTY_STR);
if (self->last == NULL) {
Py_DECREF(self);
return NULL;
}
self->number = 0;
}
return (PyObject *) self;
}
static int
Custom_init(PyObject *op, PyObject *args, PyObject *kwds)
{
CustomObject *self = (CustomObject *) op;
static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
Py_SETREF(self->first, Py_NewRef(first));
}
if (last) {
Py_SETREF(self->last, Py_NewRef(last));
}
return 0;
}
static PyMemberDef Custom_members[] = {
{"number", Py_T_INT, offsetof(CustomObject, number), 0,
"custom number"},
{NULL} /* Sentinel */
};
static PyObject *
Custom_getfirst(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->first);
}
static int
Custom_setfirst(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string");
return -1;
}
Py_XSETREF(self->first, Py_NewRef(value));
return 0;
}
static PyObject *
Custom_getlast(PyObject *op, void *closure)
{
CustomObject *self = (CustomObject *) op;
return Py_NewRef(self->last);
}
static int
Custom_setlast(PyObject *op, PyObject *value, void *closure)
{
CustomObject *self = (CustomObject *) op;
if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
return -1;
}
if (!PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError,
"The last attribute value must be a string");
return -1;
}
Py_XSETREF(self->last, Py_NewRef(value));
return 0;
}
static PyGetSetDef Custom_getsetters[] = {
{"first", Custom_getfirst, Custom_setfirst,
"first name", NULL},
{"last", Custom_getlast, Custom_setlast,
"last name", NULL},
{NULL} /* Sentinel */
};
static PyObject *
Custom_name(PyObject *op, PyObject *Py_UNUSED(dummy))
{
CustomObject *self = (CustomObject *) op;
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
static PyMethodDef Custom_methods[] = {
{"name", Custom_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject CustomType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom4.Custom",
.tp_doc = PyDoc_STR("Custom objects"),
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
.tp_new = Custom_new,
.tp_init = Custom_init,
.tp_dealloc = Custom_dealloc,
.tp_traverse = Custom_traverse,
.tp_clear = Custom_clear,
.tp_members = Custom_members,
.tp_methods = Custom_methods,
.tp_getset = Custom_getsetters,
};
static int
custom_module_exec(PyObject *m)
{
if (PyType_Ready(&CustomType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "Custom", (PyObject *) &CustomType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot custom_module_slots[] = {
{Py_mod_exec, custom_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef custom_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "custom4",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = custom_module_slots,
};
PyMODINIT_FUNC
PyInit_custom4(void)
{
return PyModuleDef_Init(&custom_module);
}
First, the traversal method lets the cyclic GC know about subobjects that could participate in cycles:
static int
Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
CustomObject *self = (CustomObject *) op;
int vret;
if (self->first) {
vret = visit(self->first, arg);
if (vret != 0)
return vret;
}
if (self->last) {
vret = visit(self->last, arg);
if (vret != 0)
return vret;
}
return 0;
}
For each subobject that can participate in cycles, we need to call the
visit()
function, which is passed to the traversal method. The
visit()
function takes as arguments the subobject and the extra argument
arg passed to the traversal method. It returns an integer value that must be
returned if it is non-zero.
Python provides a Py_VISIT()
macro that automates calling visit
functions. With Py_VISIT()
, we can minimize the amount of boilerplate
in Custom_traverse
:
static int
Custom_traverse(PyObject *op, visitproc visit, void *arg)
{
CustomObject *self = (CustomObject *) op;
Py_VISIT(self->first);
Py_VISIT(self->last);
return 0;
}
Note
The tp_traverse
implementation must name its
arguments exactly visit and arg in order to use Py_VISIT()
.
Second, we need to provide a method for clearing any subobjects that can participate in cycles:
static int
Custom_clear(PyObject *op)
{
CustomObject *self = (CustomObject *) op;
Py_CLEAR(self->first);
Py_CLEAR(self->last);
return 0;
}
Notice the use of the Py_CLEAR()
macro. It is the recommended and safe
way to clear data attributes of arbitrary types while decrementing
their reference counts. If you were to call Py_XDECREF()
instead
on the attribute before setting it to NULL
, there is a possibility
that the attribute’s destructor would call back into code that reads the
attribute again (especially if there is a reference cycle).
Note
You could emulate Py_CLEAR()
by writing:
PyObject *tmp;
tmp = self->first;
self->first = NULL;
Py_XDECREF(tmp);
Nevertheless, it is much easier and less error-prone to always
use Py_CLEAR()
when deleting an attribute. Don’t
try to micro-optimize at the expense of robustness!
The deallocator Custom_dealloc
may call arbitrary code when clearing
attributes. It means the circular GC can be triggered inside the function.
Since the GC assumes reference count is not zero, we need to untrack the object
from the GC by calling PyObject_GC_UnTrack()
before clearing members.
Here is our reimplemented deallocator using PyObject_GC_UnTrack()
and Custom_clear
:
static void
Custom_dealloc(PyObject *op)
{
PyObject_GC_UnTrack(op);
(void)Custom_clear(op);
Py_TYPE(op)->tp_free(op);
}
Finally, we add the Py_TPFLAGS_HAVE_GC
flag to the class flags:
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
That’s pretty much it. If we had written custom tp_alloc
or
tp_free
handlers, we’d need to modify them for cyclic
garbage collection. Most extensions will use the versions automatically provided.
2.5. Subclassing other types¶
It is possible to create new extension types that are derived from existing
types. It is easiest to inherit from the built in types, since an extension can
easily use the PyTypeObject
it needs. It can be difficult to share
these PyTypeObject
structures between extension modules.
In this example we will create a SubList
type that inherits from the
built-in list
type. The new type will be completely compatible with
regular lists, but will have an additional increment()
method that
increases an internal counter:
>>> import sublist
>>> s = sublist.SubList(range(3))
>>> s.extend(s)
>>> print(len(s))
6
>>> print(s.increment())
1
>>> print(s.increment())
2
#define PY_SSIZE_T_CLEAN
#include <Python.h>
typedef struct {
PyListObject list;
int state;
} SubListObject;
static PyObject *
SubList_increment(PyObject *op, PyObject *Py_UNUSED(dummy))
{
SubListObject *self = (SubListObject *) op;
self->state++;
return PyLong_FromLong(self->state);
}
static PyMethodDef SubList_methods[] = {
{"increment", SubList_increment, METH_NOARGS,
PyDoc_STR("increment state counter")},
{NULL},
};
static int
SubList_init(PyObject *op, PyObject *args, PyObject *kwds)
{
SubListObject *self = (SubListObject *) op;
if (PyList_Type.tp_init(op, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
static PyTypeObject SubListType = {
.ob_base = PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "sublist.SubList",
.tp_doc = PyDoc_STR("SubList objects"),
.tp_basicsize = sizeof(SubListObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_init = SubList_init,
.tp_methods = SubList_methods,
};
static int
sublist_module_exec(PyObject *m)
{
SubListType.tp_base = &PyList_Type;
if (PyType_Ready(&SubListType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
return -1;
}
return 0;
}
static PyModuleDef_Slot sublist_module_slots[] = {
{Py_mod_exec, sublist_module_exec},
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
{0, NULL}
};
static PyModuleDef sublist_module = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "sublist",
.m_doc = "Example module that creates an extension type.",
.m_size = 0,
.m_slots = sublist_module_slots,
};
PyMODINIT_FUNC
PyInit_sublist(void)
{
return PyModuleDef_Init(&sublist_module);
}
As you can see, the source code closely resembles the Custom
examples in
previous sections. We will break down the main differences between them.
typedef struct {
PyListObject list;
int state;
} SubListObject;
The primary difference for derived type objects is that the base type’s
object structure must be the first value. The base type will already include
the PyObject_HEAD()
at the beginning of its structure.
When a Python object is a SubList
instance, its PyObject *
pointer
can be safely cast to both PyListObject *
and SubListObject *
:
static int
SubList_init(PyObject *op, PyObject *args, PyObject *kwds)
{
SubListObject *self = (SubListObject *) op;
if (PyList_Type.tp_init(op, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
We see above how to call through to the __init__()
method of the base
type.
This pattern is important when writing a type with custom
tp_new
and tp_dealloc
members. The tp_new
handler should not actually
create the memory for the object with its tp_alloc
,
but let the base class handle it by calling its own tp_new
.
The PyTypeObject
struct supports a tp_base
specifying the type’s concrete base class. Due to cross-platform compiler
issues, you can’t fill that field directly with a reference to
PyList_Type
; it should be done in the Py_mod_exec
function:
static int
sublist_module_exec(PyObject *m)
{
SubListType.tp_base = &PyList_Type;
if (PyType_Ready(&SubListType) < 0) {
return -1;
}
if (PyModule_AddObjectRef(m, "SubList", (PyObject *) &SubListType) < 0) {
return -1;
}
return 0;
}
Before calling PyType_Ready()
, the type structure must have the
tp_base
slot filled in. When we are deriving an
existing type, it is not necessary to fill out the tp_alloc
slot with PyType_GenericNew()
– the allocation function from the base
type will be inherited.
After that, calling PyType_Ready()
and adding the type object to the
module is the same as with the basic Custom
examples.
Footnotes


Mapping Protocol

Mapping Protocol¶
See also PyObject_GetItem()
, PyObject_SetItem()
and
PyObject_DelItem()
.
-
int PyMapping_Check(PyObject *o)¶
- Part of the Stable ABI.
Return
1
if the object provides the mapping protocol or supports slicing, and0
otherwise. Note that it returns1
for Python classes with a__getitem__()
method, since in general it is impossible to determine what type of keys the class supports. This function always succeeds.
-
Py_ssize_t PyMapping_Size(PyObject *o)¶
-
Py_ssize_t PyMapping_Length(PyObject *o)¶
- Part of the Stable ABI.
Returns the number of keys in object o on success, and
-1
on failure. This is equivalent to the Python expressionlen(o)
.
-
PyObject *PyMapping_GetItemString(PyObject *o, const char *key)¶
- Return value: New reference. Part of the Stable ABI.
This is the same as
PyObject_GetItem()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.
-
int PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result)¶
- Part of the Stable ABI since version 3.13.
Variant of
PyObject_GetItem()
which doesn’t raiseKeyError
if the key is not found.If the key is found, return
1
and set *result to a new strong reference to the corresponding value. If the key is not found, return0
and set *result toNULL
; theKeyError
is silenced. If an error other thanKeyError
is raised, return-1
and set *result toNULL
.Added in version 3.13.
-
int PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result)¶
- Part of the Stable ABI since version 3.13.
This is the same as
PyMapping_GetOptionalItem()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.Added in version 3.13.
-
int PyMapping_SetItemString(PyObject *o, const char *key, PyObject *v)¶
- Part of the Stable ABI.
This is the same as
PyObject_SetItem()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.
-
int PyMapping_DelItem(PyObject *o, PyObject *key)¶
This is an alias of
PyObject_DelItem()
.
-
int PyMapping_DelItemString(PyObject *o, const char *key)¶
This is the same as
PyObject_DelItem()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.
-
int PyMapping_HasKeyWithError(PyObject *o, PyObject *key)¶
- Part of the Stable ABI since version 3.13.
Return
1
if the mapping object has the key key and0
otherwise. This is equivalent to the Python expressionkey in o
. On failure, return-1
.Added in version 3.13.
-
int PyMapping_HasKeyStringWithError(PyObject *o, const char *key)¶
- Part of the Stable ABI since version 3.13.
This is the same as
PyMapping_HasKeyWithError()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.Added in version 3.13.
-
int PyMapping_HasKey(PyObject *o, PyObject *key)¶
- Part of the Stable ABI.
Return
1
if the mapping object has the key key and0
otherwise. This is equivalent to the Python expressionkey in o
. This function always succeeds.Note
Exceptions which occur when this calls the
__getitem__()
method are silently ignored. For proper error handling, usePyMapping_HasKeyWithError()
,PyMapping_GetOptionalItem()
orPyObject_GetItem()
instead.
-
int PyMapping_HasKeyString(PyObject *o, const char *key)¶
- Part of the Stable ABI.
This is the same as
PyMapping_HasKey()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.Note
Exceptions that occur when this calls the
__getitem__()
method or while creating the temporarystr
object are silently ignored. For proper error handling, usePyMapping_HasKeyStringWithError()
,PyMapping_GetOptionalItemString()
orPyMapping_GetItemString()
instead.
-
PyObject *PyMapping_Keys(PyObject *o)¶
- Return value: New reference. Part of the Stable ABI.
On success, return a list of the keys in object o. On failure, return
NULL
.Changed in version 3.7: Previously, the function returned a list or a tuple.
-
PyObject *PyMapping_Values(PyObject *o)¶
- Return value: New reference. Part of the Stable ABI.
On success, return a list of the values in object o. On failure, return
NULL
.Changed in version 3.7: Previously, the function returned a list or a tuple.
-
PyObject *PyMapping_Items(PyObject *o)¶
- Return value: New reference. Part of the Stable ABI.
On success, return a list of the items in object o, where each item is a tuple containing a key-value pair. On failure, return
NULL
.Changed in version 3.7: Previously, the function returned a list or a tuple.


Dictionary Objects

Dictionary Objects¶
-
PyTypeObject PyDict_Type¶
- Part of the Stable ABI.
This instance of
PyTypeObject
represents the Python dictionary type. This is the same object asdict
in the Python layer.
-
int PyDict_Check(PyObject *p)¶
Return true if p is a dict object or an instance of a subtype of the dict type. This function always succeeds.
-
int PyDict_CheckExact(PyObject *p)¶
Return true if p is a dict object, but not an instance of a subtype of the dict type. This function always succeeds.
-
PyObject *PyDict_New()¶
- Return value: New reference. Part of the Stable ABI.
Return a new empty dictionary, or
NULL
on failure.
-
PyObject *PyDictProxy_New(PyObject *mapping)¶
- Return value: New reference. Part of the Stable ABI.
Return a
types.MappingProxyType
object for a mapping which enforces read-only behavior. This is normally used to create a view to prevent modification of the dictionary for non-dynamic class types.
-
PyTypeObject PyDictProxy_Type¶
- Part of the Stable ABI.
The type object for mapping proxy objects created by
PyDictProxy_New()
and for the read-only__dict__
attribute of many built-in types. APyDictProxy_Type
instance provides a dynamic, read-only view of an underlying dictionary: changes to the underlying dictionary are reflected in the proxy, but the proxy itself does not support mutation operations. This corresponds totypes.MappingProxyType
in Python.
-
void PyDict_Clear(PyObject *p)¶
- Part of the Stable ABI.
Empty an existing dictionary of all key-value pairs.
-
int PyDict_Contains(PyObject *p, PyObject *key)¶
- Part of the Stable ABI.
Determine if dictionary p contains key. If an item in p matches key, return
1
, otherwise return0
. On error, return-1
. This is equivalent to the Python expressionkey in p
.
-
int PyDict_ContainsString(PyObject *p, const char *key)¶
This is the same as
PyDict_Contains()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.Added in version 3.13.
-
PyObject *PyDict_Copy(PyObject *p)¶
- Return value: New reference. Part of the Stable ABI.
Return a new dictionary that contains the same key-value pairs as p.
-
int PyDict_SetItem(PyObject *p, PyObject *key, PyObject *val)¶
- Part of the Stable ABI.
Insert val into the dictionary p with a key of key. key must be hashable; if it isn’t,
TypeError
will be raised. Return0
on success or-1
on failure. This function does not steal a reference to val.
-
int PyDict_SetItemString(PyObject *p, const char *key, PyObject *val)¶
- Part of the Stable ABI.
This is the same as
PyDict_SetItem()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.
-
int PyDict_DelItem(PyObject *p, PyObject *key)¶
- Part of the Stable ABI.
Remove the entry in dictionary p with key key. key must be hashable; if it isn’t,
TypeError
is raised. If key is not in the dictionary,KeyError
is raised. Return0
on success or-1
on failure.
-
int PyDict_DelItemString(PyObject *p, const char *key)¶
- Part of the Stable ABI.
This is the same as
PyDict_DelItem()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.
-
int PyDict_GetItemRef(PyObject *p, PyObject *key, PyObject **result)¶
- Part of the Stable ABI since version 3.13.
Return a new strong reference to the object from dictionary p which has a key key:
If the key is present, set *result to a new strong reference to the value and return
1
.If the key is missing, set *result to
NULL
and return0
.On error, raise an exception and return
-1
.
Added in version 3.13.
See also the
PyObject_GetItem()
function.
-
PyObject *PyDict_GetItem(PyObject *p, PyObject *key)¶
- Return value: Borrowed reference. Part of the Stable ABI.
Return a borrowed reference to the object from dictionary p which has a key key. Return
NULL
if the key key is missing without setting an exception.Note
Exceptions that occur while this calls
__hash__()
and__eq__()
methods are silently ignored. Prefer thePyDict_GetItemWithError()
function instead.Changed in version 3.10: Calling this API without an attached thread state had been allowed for historical reason. It is no longer allowed.
-
PyObject *PyDict_GetItemWithError(PyObject *p, PyObject *key)¶
- Return value: Borrowed reference. Part of the Stable ABI.
Variant of
PyDict_GetItem()
that does not suppress exceptions. ReturnNULL
with an exception set if an exception occurred. ReturnNULL
without an exception set if the key wasn’t present.
-
PyObject *PyDict_GetItemString(PyObject *p, const char *key)¶
- Return value: Borrowed reference. Part of the Stable ABI.
This is the same as
PyDict_GetItem()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.Note
Exceptions that occur while this calls
__hash__()
and__eq__()
methods or while creating the temporarystr
object are silently ignored. Prefer using thePyDict_GetItemWithError()
function with your ownPyUnicode_FromString()
key instead.
-
int PyDict_GetItemStringRef(PyObject *p, const char *key, PyObject **result)¶
- Part of the Stable ABI since version 3.13.
Similar to
PyDict_GetItemRef()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.Added in version 3.13.
-
PyObject *PyDict_SetDefault(PyObject *p, PyObject *key, PyObject *defaultobj)¶
- Return value: Borrowed reference.
This is the same as the Python-level
dict.setdefault()
. If present, it returns the value corresponding to key from the dictionary p. If the key is not in the dict, it is inserted with value defaultobj and defaultobj is returned. This function evaluates the hash function of key only once, instead of evaluating it independently for the lookup and the insertion.Added in version 3.4.
-
int PyDict_SetDefaultRef(PyObject *p, PyObject *key, PyObject *default_value, PyObject **result)¶
Inserts default_value into the dictionary p with a key of key if the key is not already present in the dictionary. If result is not
NULL
, then *result is set to a strong reference to either default_value, if the key was not present, or the existing value, if key was already present in the dictionary. Returns1
if the key was present and default_value was not inserted, or0
if the key was not present and default_value was inserted. On failure, returns-1
, sets an exception, and sets*result
toNULL
.For clarity: if you have a strong reference to default_value before calling this function, then after it returns, you hold a strong reference to both default_value and *result (if it’s not
NULL
). These may refer to the same object: in that case you hold two separate references to it.Added in version 3.13.
-
int PyDict_Pop(PyObject *p, PyObject *key, PyObject **result)¶
Remove key from dictionary p and optionally return the removed value. Do not raise
KeyError
if the key is missing.If the key is present, set *result to a new reference to the removed value if result is not
NULL
, and return1
.If the key is missing, set *result to
NULL
if result is notNULL
, and return0
.On error, raise an exception and return
-1
.
Similar to
dict.pop()
, but without the default value and not raisingKeyError
if the key is missing.Added in version 3.13.
-
int PyDict_PopString(PyObject *p, const char *key, PyObject **result)¶
Similar to
PyDict_Pop()
, but key is specified as a const char* UTF-8 encoded bytes string, rather than a PyObject*.Added in version 3.13.
-
PyObject *PyDict_Items(PyObject *p)¶
- Return value: New reference. Part of the Stable ABI.
Return a
PyListObject
containing all the items from the dictionary.
-
PyObject *PyDict_Keys(PyObject *p)¶
- Return value: New reference. Part of the Stable ABI.
Return a
PyListObject
containing all the keys from the dictionary.
-
PyObject *PyDict_Values(PyObject *p)¶
- Return value: New reference. Part of the Stable ABI.
Return a
PyListObject
containing all the values from the dictionary p.
-
Py_ssize_t PyDict_Size(PyObject *p)¶
- Part of the Stable ABI.
Return the number of items in the dictionary. This is equivalent to
len(p)
on a dictionary.
-
Py_ssize_t PyDict_GET_SIZE(PyObject *p)¶
Similar to
PyDict_Size()
, but without error checking.
-
int PyDict_Next(PyObject *p, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)¶
- Part of the Stable ABI.
Iterate over all key-value pairs in the dictionary p. The
Py_ssize_t
referred to by ppos must be initialized to0
prior to the first call to this function to start the iteration; the function returns true for each pair in the dictionary, and false once all pairs have been reported. The parameters pkey and pvalue should either point to PyObject* variables that will be filled in with each key and value, respectively, or may beNULL
. Any references returned through them are borrowed. ppos should not be altered during iteration. Its value represents offsets within the internal dictionary structure, and since the structure is sparse, the offsets are not consecutive.For example:
PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(self->dict, &pos, &key, &value)) { /* do something interesting with the values... */ ... }
The dictionary p should not be mutated during iteration. It is safe to modify the values of the keys as you iterate over the dictionary, but only so long as the set of keys does not change. For example:
PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(self->dict, &pos, &key, &value)) { long i = PyLong_AsLong(value); if (i == -1 && PyErr_Occurred()) { return -1; } PyObject *o = PyLong_FromLong(i + 1); if (o == NULL) return -1; if (PyDict_SetItem(self->dict, key, o) < 0) { Py_DECREF(o); return -1; } Py_DECREF(o); }
The function is not thread-safe in the free-threaded build without external synchronization. You can use
Py_BEGIN_CRITICAL_SECTION
to lock the dictionary while iterating over it:Py_BEGIN_CRITICAL_SECTION(self->dict); while (PyDict_Next(self->dict, &pos, &key, &value)) { ... } Py_END_CRITICAL_SECTION();
Note
On the free-threaded build, this function can be used safely inside a critical section. However, the references returned for pkey and pvalue are borrowed and are only valid while the critical section is held. If you need to use these objects outside the critical section or when the critical section can be suspended, create a strong reference (for example, using
Py_NewRef()
).
-
int PyDict_Merge(PyObject *a, PyObject *b, int override)¶
- Part of the Stable ABI.
Iterate over mapping object b adding key-value pairs to dictionary a. b may be a dictionary, or any object supporting
PyMapping_Keys()
andPyObject_GetItem()
. If override is true, existing pairs in a will be replaced if a matching key is found in b, otherwise pairs will only be added if there is not a matching key in a. Return0
on success or-1
if an exception was raised.
-
int PyDict_Update(PyObject *a, PyObject *b)¶
- Part of the Stable ABI.
This is the same as
PyDict_Merge(a, b, 1)
in C, and is similar toa.update(b)
in Python except thatPyDict_Update()
doesn’t fall back to the iterating over a sequence of key value pairs if the second argument has no “keys” attribute. Return0
on success or-1
if an exception was raised.
-
int PyDict_MergeFromSeq2(PyObject *a, PyObject *seq2, int override)¶
- Part of the Stable ABI.
Update or merge into dictionary a, from the key-value pairs in seq2. seq2 must be an iterable object producing iterable objects of length 2, viewed as key-value pairs. In case of duplicate keys, the last wins if override is true, else the first wins. Return
0
on success or-1
if an exception was raised. Equivalent Python (except for the return value):def PyDict_MergeFromSeq2(a, seq2, override): for key, value in seq2: if override or key not in a: a[key] = value
-
int PyDict_AddWatcher(PyDict_WatchCallback callback)¶
Register callback as a dictionary watcher. Return a non-negative integer id which must be passed to future calls to
PyDict_Watch()
. In case of error (e.g. no more watcher IDs available), return-1
and set an exception.Added in version 3.12.
-
int PyDict_ClearWatcher(int watcher_id)¶
Clear watcher identified by watcher_id previously returned from
PyDict_AddWatcher()
. Return0
on success,-1
on error (e.g. if the given watcher_id was never registered.)Added in version 3.12.
-
int PyDict_Watch(int watcher_id, PyObject *dict)¶
Mark dictionary dict as watched. The callback granted watcher_id by
PyDict_AddWatcher()
will be called when dict is modified or deallocated. Return0
on success or-1
on error.Added in version 3.12.
-
int PyDict_Unwatch(int watcher_id, PyObject *dict)¶
Mark dictionary dict as no longer watched. The callback granted watcher_id by
PyDict_AddWatcher()
will no longer be called when dict is modified or deallocated. The dict must previously have been watched by this watcher. Return0
on success or-1
on error.Added in version 3.12.
-
type PyDict_WatchEvent¶
Enumeration of possible dictionary watcher events:
PyDict_EVENT_ADDED
,PyDict_EVENT_MODIFIED
,PyDict_EVENT_DELETED
,PyDict_EVENT_CLONED
,PyDict_EVENT_CLEARED
, orPyDict_EVENT_DEALLOCATED
.Added in version 3.12.
-
typedef int (*PyDict_WatchCallback)(PyDict_WatchEvent event, PyObject *dict, PyObject *key, PyObject *new_value)¶
Type of a dict watcher callback function.
If event is
PyDict_EVENT_CLEARED
orPyDict_EVENT_DEALLOCATED
, both key and new_value will beNULL
. If event isPyDict_EVENT_ADDED
orPyDict_EVENT_MODIFIED
, new_value will be the new value for key. If event isPyDict_EVENT_DELETED
, key is being deleted from the dictionary and new_value will beNULL
.PyDict_EVENT_CLONED
occurs when dict was previously empty and another dict is merged into it. To maintain efficiency of this operation, per-keyPyDict_EVENT_ADDED
events are not issued in this case; instead a singlePyDict_EVENT_CLONED
is issued, and key will be the source dictionary.The callback may inspect but must not modify dict; doing so could have unpredictable effects, including infinite recursion. Do not trigger Python code execution in the callback, as it could modify the dict as a side effect.
If event is
PyDict_EVENT_DEALLOCATED
, taking a new reference in the callback to the about-to-be-destroyed dictionary will resurrect it and prevent it from being freed at this time. When the resurrected object is destroyed later, any watcher callbacks active at that time will be called again.Callbacks occur before the notified modification to dict takes place, so the prior state of dict can be inspected.
If the callback sets an exception, it must return
-1
; this exception will be printed as an unraisable exception usingPyErr_WriteUnraisable()
. Otherwise it should return0
.There may already be a pending exception set on entry to the callback. In this case, the callback should return
0
with the same exception still set. This means the callback may not call any other API that can set an exception unless it saves and clears the exception state first, and restores it before returning.Added in version 3.12.
Dictionary View Objects¶
-
int PyDictViewSet_Check(PyObject *op)¶
Return true if op is a view of a set inside a dictionary. This is currently equivalent to PyDictKeys_Check(op) || PyDictItems_Check(op). This function always succeeds.
-
PyTypeObject PyDictKeys_Type¶
- Part of the Stable ABI.
Type object for a view of dictionary keys. In Python, this is the type of the object returned by
dict.keys()
.
-
int PyDictKeys_Check(PyObject *op)¶
Return true if op is an instance of a dictionary keys view. This function always succeeds.
-
PyTypeObject PyDictValues_Type¶
- Part of the Stable ABI.
Type object for a view of dictionary values. In Python, this is the type of the object returned by
dict.values()
.
-
int PyDictValues_Check(PyObject *op)¶
Return true if op is an instance of a dictionary values view. This function always succeeds.
-
PyTypeObject PyDictItems_Type¶
- Part of the Stable ABI.
Type object for a view of dictionary items. In Python, this is the type of the object returned by
dict.items()
.
Ordered Dictionaries¶
Python’s C API provides interface for collections.OrderedDict
from C.
Since Python 3.7, dictionaries are ordered by default, so there is usually
little need for these functions; prefer PyDict*
where possible.
-
PyTypeObject PyODict_Type¶
Type object for ordered dictionaries. This is the same object as
collections.OrderedDict
in the Python layer.
-
int PyODict_Check(PyObject *od)¶
Return true if od is an ordered dictionary object or an instance of a subtype of the
OrderedDict
type. This function always succeeds.
-
int PyODict_CheckExact(PyObject *od)¶
Return true if od is an ordered dictionary object, but not an instance of a subtype of the
OrderedDict
type. This function always succeeds.
-
PyTypeObject PyODictKeys_Type¶
Analogous to
PyDictKeys_Type
for ordered dictionaries.
-
PyTypeObject PyODictValues_Type¶
Analogous to
PyDictValues_Type
for ordered dictionaries.
-
PyTypeObject PyODictItems_Type¶
Analogous to
PyDictItems_Type
for ordered dictionaries.
-
PyObject *PyODict_New(void)¶
Return a new empty ordered dictionary, or
NULL
on failure.This is analogous to
PyDict_New()
.
-
int PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value)¶
Insert value into the ordered dictionary od with a key of key. Return
0
on success or-1
with an exception set on failure.This is analogous to
PyDict_SetItem()
.
-
int PyODict_DelItem(PyObject *od, PyObject *key)¶
Remove the entry in the ordered dictionary od with key key. Return
0
on success or-1
with an exception set on failure.This is analogous to
PyDict_DelItem()
.
These are soft deprecated aliases to PyDict
APIs:
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|


The

The None
Object¶
Note that the PyTypeObject
for None
is not directly exposed in the
Python/C API. Since None
is a singleton, testing for object identity (using
==
in C) is sufficient. There is no PyNone_Check()
function for the
same reason.


— Encode and decode uuencode files

uu
— Encode and decode uuencode files¶
Deprecated since version 3.11, removed in version 3.13.
This module is no longer part of the Python standard library. It was removed in Python 3.13 after being deprecated in Python 3.11. The removal was decided in PEP 594.
The last version of Python that provided the uu
module was
Python 3.12.


— Telnet client

telnetlib
— Telnet client¶
Deprecated since version 3.11, removed in version 3.13.
This module is no longer part of the Python standard library. It was removed in Python 3.13 after being deprecated in Python 3.11. The removal was decided in PEP 594.
Possible replacements are third-party libraries from PyPI: telnetlib3 or Exscript. These are not supported or maintained by the Python core team.
The last version of Python that provided the telnetlib
module was
Python 3.12.


— Read and write Sun AU files

sunau
— Read and write Sun AU files¶
Deprecated since version 3.11, removed in version 3.13.
This module is no longer part of the Python standard library. It was removed in Python 3.13 after being deprecated in Python 3.11. The removal was decided in PEP 594.
The last version of Python that provided the sunau
module was
Python 3.12.


— The shadow password database

spwd
— The shadow password database¶
Deprecated since version 3.11, removed in version 3.13.
This module is no longer part of the Python standard library. It was removed in Python 3.13 after being deprecated in Python 3.11. The removal was decided in PEP 594.
A possible replacement is the third-party library python-pam. This library is not supported or maintained by the Python core team.
The last version of Python that provided the spwd
module was
Python 3.12.


— Determine type of sound file

sndhdr
— Determine type of sound file¶
Deprecated since version 3.11, removed in version 3.13.
This module is no longer part of the Python standard library. It was removed in Python 3.13 after being deprecated in Python 3.11. The removal was decided in PEP 594.
Possible replacements are third-party modules from PyPI: filetype, puremagic, or python-magic. These are not supported or maintained by the Python core team.
The last version of Python that provided the sndhdr
module was
Python 3.12.


— SMTP Server

smtpd
— SMTP Server¶
Deprecated since version 3.6, removed in version 3.12.
This module is no longer part of the Python standard library. It was removed in Python 3.12 after being deprecated in Python 3.6. The removal was decided in PEP 594.
A possible replacement is the third-party aiosmtpd library. This library is not maintained or supported by the Python core team.
The last version of Python that provided the smtpd
module was
Python 3.11.


— Interface to shell pipelines

pipes
— Interface to shell pipelines¶
Deprecated since version 3.11, removed in version 3.13.
This module is no longer part of the Python standard library. It was removed in Python 3.13 after being deprecated in Python 3.11. The removal was decided in PEP 594.
Applications should use the subprocess
module instead.
The last version of Python that provided the pipes
module was
Python 3.12.


Futures

Futures¶
Source code: Lib/asyncio/futures.py, Lib/asyncio/base_futures.py
Future objects are used to bridge low-level callback-based code with high-level async/await code.
Future Functions¶
- asyncio.isfuture(obj)¶
Return
True
if obj is either of:an instance of
asyncio.Future
,an instance of
asyncio.Task
,a Future-like object with a
_asyncio_future_blocking
attribute.
Added in version 3.5.
- asyncio.ensure_future(obj, *, loop=None)¶
Return:
obj argument as is, if obj is a
Future
, aTask
, or a Future-like object (isfuture()
is used for the test.)a
Task
object wrapping obj, if obj is a coroutine (iscoroutine()
is used for the test); in this case the coroutine will be scheduled byensure_future()
.a
Task
object that would await on obj, if obj is an awaitable (inspect.isawaitable()
is used for the test.)
If obj is neither of the above a
TypeError
is raised.Important
Save a reference to the result of this function, to avoid a task disappearing mid-execution.
See also the
create_task()
function which is the preferred way for creating new tasks or useasyncio.TaskGroup
which keeps reference to the task internally.Changed in version 3.5.1: The function accepts any awaitable object.
Deprecated since version 3.10: Deprecation warning is emitted if obj is not a Future-like object and loop is not specified and there is no running event loop.
- asyncio.wrap_future(future, *, loop=None)¶
Wrap a
concurrent.futures.Future
object in aasyncio.Future
object.Deprecated since version 3.10: Deprecation warning is emitted if future is not a Future-like object and loop is not specified and there is no running event loop.
Future Object¶
- class asyncio.Future(*, loop=None)¶
A Future represents an eventual result of an asynchronous operation. Not thread-safe.
Future is an awaitable object. Coroutines can await on Future objects until they either have a result or an exception set, or until they are cancelled. A Future can be awaited multiple times and the result is same.
Typically Futures are used to enable low-level callback-based code (e.g. in protocols implemented using asyncio transports) to interoperate with high-level async/await code.
The rule of thumb is to never expose Future objects in user-facing APIs, and the recommended way to create a Future object is to call
loop.create_future()
. This way alternative event loop implementations can inject their own optimized implementations of a Future object.Changed in version 3.7: Added support for the
contextvars
module.Deprecated since version 3.10: Deprecation warning is emitted if loop is not specified and there is no running event loop.
- result()¶
Return the result of the Future.
If the Future is done and has a result set by the
set_result()
method, the result value is returned.If the Future is done and has an exception set by the
set_exception()
method, this method raises the exception.If the Future has been cancelled, this method raises a
CancelledError
exception.If the Future’s result isn’t yet available, this method raises an
InvalidStateError
exception.
- set_result(result)¶
Mark the Future as done and set its result.
Raises an
InvalidStateError
error if the Future is already done.
- set_exception(exception)¶
Mark the Future as done and set an exception.
Raises an
InvalidStateError
error if the Future is already done.
- done()¶
Return
True
if the Future is done.A Future is done if it was cancelled or if it has a result or an exception set with
set_result()
orset_exception()
calls.
- cancelled()¶
Return
True
if the Future was cancelled.The method is usually used to check if a Future is not cancelled before setting a result or an exception for it:
if not fut.cancelled(): fut.set_result(42)
- add_done_callback(callback, *, context=None)¶
Add a callback to be run when the Future is done.
The callback is called with the Future object as its only argument.
If the Future is already done when this method is called, the callback is scheduled with
loop.call_soon()
.An optional keyword-only context argument allows specifying a custom
contextvars.Context
for the callback to run in. The current context is used when no context is provided.functools.partial()
can be used to pass parameters to the callback, e.g.:# Call 'print("Future:", fut)' when "fut" is done. fut.add_done_callback( functools.partial(print, "Future:"))
Changed in version 3.7: The context keyword-only parameter was added. See PEP 567 for more details.
- remove_done_callback(callback)¶
Remove callback from the callbacks list.
Returns the number of callbacks removed, which is typically 1, unless a callback was added more than once.
- cancel(msg=None)¶
Cancel the Future and schedule callbacks.
If the Future is already done or cancelled, return
False
. Otherwise, change the Future’s state to cancelled, schedule the callbacks, and returnTrue
.Changed in version 3.9: Added the msg parameter.
- exception()¶
Return the exception that was set on this Future.
The exception (or
None
if no exception was set) is returned only if the Future is done.If the Future has been cancelled, this method raises a
CancelledError
exception.If the Future isn’t done yet, this method raises an
InvalidStateError
exception.
- get_loop()¶
Return the event loop the Future object is bound to.
Added in version 3.7.
This example creates a Future object, creates and schedules an asynchronous Task to set result for the Future, and waits until the Future has a result:
async def set_after(fut, delay, value):
# Sleep for *delay* seconds.
await asyncio.sleep(delay)
# Set *value* as a result of *fut* Future.
fut.set_result(value)
async def main():
# Get the current event loop.
loop = asyncio.get_running_loop()
# Create a new Future object.
fut = loop.create_future()
# Run "set_after()" coroutine in a parallel Task.
# We are using the low-level "loop.create_task()" API here because
# we already have a reference to the event loop at hand.
# Otherwise we could have just used "asyncio.create_task()".
loop.create_task(
set_after(fut, 1, '... world'))
print('hello ...')
# Wait until *fut* has a result (1 second) and print it.
print(await fut)
asyncio.run(main())
Important
The Future object was designed to mimic
concurrent.futures.Future
. Key differences include:
unlike asyncio Futures,
concurrent.futures.Future
instances cannot be awaited.asyncio.Future.result()
andasyncio.Future.exception()
do not accept the timeout argument.asyncio.Future.result()
andasyncio.Future.exception()
raise anInvalidStateError
exception when the Future is not done.Callbacks registered with
asyncio.Future.add_done_callback()
are not called immediately. They are scheduled withloop.call_soon()
instead.asyncio Future is not compatible with the
concurrent.futures.wait()
andconcurrent.futures.as_completed()
functions.asyncio.Future.cancel()
accepts an optionalmsg
argument, butconcurrent.futures.Future.cancel()
does not.