Extending and Embedding Python, Release 3.9.5 31 2.2. Defining Extension Types: Tutorial (continued from previous page) and put the definitions in the$_{tp_members}$ slot: .tp_members=Custom_members, 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: 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? 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 release the Global interpreter Lock and let arbitrary code run in other threads that accesses and modifies our object. 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: .tp_init=(initproc) Custom_init, by filling the tp_init slot. Py_INCREF(last); self->last=last; Py_XDECREF(tmp); } return 0; } if (first) { Py_XDECREF(self ->first); Py_INCREF(first); self->first =first; } • when we absolutely know that the reference count is greater than 1; • when we know that deallocation of the object 1 will neither release the GIL 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}$. static PyMemberDef Custom_members[]={ { "first", T_OBJECT_EX, offsetof(CustomObject, first), 0, "first name"}, { "last", T_OBJECT_EX, offsetof(CustomObject, last), 0, "last name "}, { "number", T_INT, offsetof(CustomObject, number), 0, "custom number "}, { NULL } /* Sentinel */ }; 2 We relied on this in the tp_dealloc handler in this example, because our type doesn’t support garbage collection. 1 This is true when we know that the object is a basic type, like a string or a float.