Extending and Embedding Python, Release 3.9.5 Chapter 2. Creating extensions without third party tools 36 We create an array of$_{PyGetSetDef}$ structures: 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. 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.) 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: (continued from previous page) PyMODINIT_FUNC PyInit_custom3 ( void ) { PyObject *m; if (PyType_Ready( &CustomType)<0) return NULL ; m =PyModule_Create(&custommodule); if (m==NULL ) return NULL ; Py_INCREF(&CustomType); if (PyModule_AddObject(m, "Custom", (PyObject*)&CustomType)<0) { Py_DECREF( &CustomType); Py_DECREF(m); return NULL ; } return m; } static PyObject * Custom_getfirst(CustomObject *self, void *closure) { Py_INCREF(self->first); return self->first; } static int Custom_setfirst(CustomObject *self, PyObject*value, void *closure) { 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; }