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(newdatatypeobject *obj) { return PyUnicode_FromFormat("Stringified_newdatatype{{size:%d}}", obj->obj_UnderlyingDatatypePtr ->size); } getattrfunc tp_getattr; /* char * version */ setattrfunc tp_setattr; /* ... */ getattrofunc tp_getattro; /* PyObject * version */ setattrofunc tp_setattro; structPyMethodDef *tp_methods; structPyMemberDef *tp_members; structPyGetSetDef *tp_getset; Extending and Embedding Python, Release 3.9.5 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. 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. Most extension types only use simple attributes. So, what makes the attributes simple? There are only a couple of conditions that must be met: 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 descriptor s 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: Generic Attribute Management 1. The name of the attributes must be known when$_{PyType_Ready()}$ is called. 2. 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. 2.3.3 Attribute Management 2.3. Defining Extension Types: Assorted Topics 49