1#define PY_SSIZE_T_CLEAN 2#include <Python.h> 3#include "structmember.h" 4 5typedef struct { 6 PyObject_HEAD 7 PyObject *first; /* first name */ 8 PyObject *last; /* last name */ 9 int number; 10} CustomObject; 11 12static int 13Custom_traverse(CustomObject *self, visitproc visit, void *arg) 14{ 15 Py_VISIT(self->first); 16 Py_VISIT(self->last); 17 return 0; 18} 19 20static int 21Custom_clear(CustomObject *self) 22{ 23 Py_CLEAR(self->first); 24 Py_CLEAR(self->last); 25 return 0; 26} 27 28static void 29Custom_dealloc(CustomObject *self) 30{ 31 PyObject_GC_UnTrack(self); 32 Custom_clear(self); 33 Py_TYPE(self)->tp_free((PyObject *) self); 34} 35 36static PyObject * 37Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) 38{ 39 CustomObject *self; 40 self = (CustomObject *) type->tp_alloc(type, 0); 41 if (self != NULL) { 42 self->first = PyUnicode_FromString(""); 43 if (self->first == NULL) { 44 Py_DECREF(self); 45 return NULL; 46 } 47 self->last = PyUnicode_FromString(""); 48 if (self->last == NULL) { 49 Py_DECREF(self); 50 return NULL; 51 } 52 self->number = 0; 53 } 54 return (PyObject *) self; 55} 56 57static int 58Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) 59{ 60 static char *kwlist[] = {"first", "last", "number", NULL}; 61 PyObject *first = NULL, *last = NULL, *tmp; 62 63 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, 64 &first, &last, 65 &self->number)) 66 return -1; 67 68 if (first) { 69 tmp = self->first; 70 Py_INCREF(first); 71 self->first = first; 72 Py_DECREF(tmp); 73 } 74 if (last) { 75 tmp = self->last; 76 Py_INCREF(last); 77 self->last = last; 78 Py_DECREF(tmp); 79 } 80 return 0; 81} 82 83static PyMemberDef Custom_members[] = { 84 {"number", T_INT, offsetof(CustomObject, number), 0, 85 "custom number"}, 86 {NULL} /* Sentinel */ 87}; 88 89static PyObject * 90Custom_getfirst(CustomObject *self, void *closure) 91{ 92 Py_INCREF(self->first); 93 return self->first; 94} 95 96static int 97Custom_setfirst(CustomObject *self, PyObject *value, void *closure) 98{ 99 if (value == NULL) { 100 PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); 101 return -1; 102 } 103 if (!PyUnicode_Check(value)) { 104 PyErr_SetString(PyExc_TypeError, 105 "The first attribute value must be a string"); 106 return -1; 107 } 108 Py_INCREF(value); 109 Py_CLEAR(self->first); 110 self->first = value; 111 return 0; 112} 113 114static PyObject * 115Custom_getlast(CustomObject *self, void *closure) 116{ 117 Py_INCREF(self->last); 118 return self->last; 119} 120 121static int 122Custom_setlast(CustomObject *self, PyObject *value, void *closure) 123{ 124 if (value == NULL) { 125 PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); 126 return -1; 127 } 128 if (!PyUnicode_Check(value)) { 129 PyErr_SetString(PyExc_TypeError, 130 "The last attribute value must be a string"); 131 return -1; 132 } 133 Py_INCREF(value); 134 Py_CLEAR(self->last); 135 self->last = value; 136 return 0; 137} 138 139static PyGetSetDef Custom_getsetters[] = { 140 {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, 141 "first name", NULL}, 142 {"last", (getter) Custom_getlast, (setter) Custom_setlast, 143 "last name", NULL}, 144 {NULL} /* Sentinel */ 145}; 146 147static PyObject * 148Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) 149{ 150 return PyUnicode_FromFormat("%S %S", self->first, self->last); 151} 152 153static PyMethodDef Custom_methods[] = { 154 {"name", (PyCFunction) Custom_name, METH_NOARGS, 155 "Return the name, combining the first and last name" 156 }, 157 {NULL} /* Sentinel */ 158}; 159 160static PyTypeObject CustomType = { 161 PyVarObject_HEAD_INIT(NULL, 0) 162 .tp_name = "custom4.Custom", 163 .tp_doc = PyDoc_STR("Custom objects"), 164 .tp_basicsize = sizeof(CustomObject), 165 .tp_itemsize = 0, 166 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, 167 .tp_new = Custom_new, 168 .tp_init = (initproc) Custom_init, 169 .tp_dealloc = (destructor) Custom_dealloc, 170 .tp_traverse = (traverseproc) Custom_traverse, 171 .tp_clear = (inquiry) Custom_clear, 172 .tp_members = Custom_members, 173 .tp_methods = Custom_methods, 174 .tp_getset = Custom_getsetters, 175}; 176 177static PyModuleDef custommodule = { 178 PyModuleDef_HEAD_INIT, 179 .m_name = "custom4", 180 .m_doc = "Example module that creates an extension type.", 181 .m_size = -1, 182}; 183 184PyMODINIT_FUNC 185PyInit_custom4(void) 186{ 187 PyObject *m; 188 if (PyType_Ready(&CustomType) < 0) 189 return NULL; 190 191 m = PyModule_Create(&custommodule); 192 if (m == NULL) 193 return NULL; 194 195 Py_INCREF(&CustomType); 196 if (PyModule_AddObject(m, "Custom", (PyObject *) &CustomType) < 0) { 197 Py_DECREF(&CustomType); 198 Py_DECREF(m); 199 return NULL; 200 } 201 202 return m; 203} 204