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