| #define PY_SSIZE_T_CLEAN |
| #include <Python.h> |
| #include "structmember.h" |
| |
| typedef struct { |
| PyObject_HEAD |
| PyObject *first; /* first name */ |
| PyObject *last; /* last name */ |
| int number; |
| } CustomObject; |
| |
| static int |
| Custom_traverse(CustomObject *self, visitproc visit, void *arg) |
| { |
| Py_VISIT(self->first); |
| Py_VISIT(self->last); |
| return 0; |
| } |
| |
| static int |
| Custom_clear(CustomObject *self) |
| { |
| Py_CLEAR(self->first); |
| Py_CLEAR(self->last); |
| return 0; |
| } |
| |
| static void |
| Custom_dealloc(CustomObject *self) |
| { |
| PyObject_GC_UnTrack(self); |
| Custom_clear(self); |
| Py_TYPE(self)->tp_free((PyObject *) self); |
| } |
| |
| static PyObject * |
| Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
| { |
| CustomObject *self; |
| self = (CustomObject *) type->tp_alloc(type, 0); |
| if (self != NULL) { |
| self->first = PyUnicode_FromString(""); |
| if (self->first == NULL) { |
| Py_DECREF(self); |
| return NULL; |
| } |
| self->last = PyUnicode_FromString(""); |
| if (self->last == NULL) { |
| Py_DECREF(self); |
| return NULL; |
| } |
| self->number = 0; |
| } |
| return (PyObject *) self; |
| } |
| |
| static int |
| Custom_init(CustomObject *self, PyObject *args, PyObject *kwds) |
| { |
| static char *kwlist[] = {"first", "last", "number", NULL}; |
| PyObject *first = NULL, *last = NULL, *tmp; |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist, |
| &first, &last, |
| &self->number)) |
| return -1; |
| |
| if (first) { |
| tmp = self->first; |
| Py_INCREF(first); |
| self->first = first; |
| Py_DECREF(tmp); |
| } |
| if (last) { |
| tmp = self->last; |
| Py_INCREF(last); |
| self->last = last; |
| Py_DECREF(tmp); |
| } |
| return 0; |
| } |
| |
| static PyMemberDef Custom_members[] = { |
| {"number", T_INT, offsetof(CustomObject, number), 0, |
| "custom number"}, |
| {NULL} /* Sentinel */ |
| }; |
| |
| 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) |
| { |
| 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; |
| } |
| Py_INCREF(value); |
| Py_CLEAR(self->first); |
| self->first = value; |
| return 0; |
| } |
| |
| static PyObject * |
| Custom_getlast(CustomObject *self, void *closure) |
| { |
| Py_INCREF(self->last); |
| return self->last; |
| } |
| |
| static int |
| Custom_setlast(CustomObject *self, PyObject *value, void *closure) |
| { |
| if (value == NULL) { |
| PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); |
| return -1; |
| } |
| if (!PyUnicode_Check(value)) { |
| PyErr_SetString(PyExc_TypeError, |
| "The last attribute value must be a string"); |
| return -1; |
| } |
| Py_INCREF(value); |
| Py_CLEAR(self->last); |
| self->last = value; |
| return 0; |
| } |
| |
| static PyGetSetDef Custom_getsetters[] = { |
| {"first", (getter) Custom_getfirst, (setter) Custom_setfirst, |
| "first name", NULL}, |
| {"last", (getter) Custom_getlast, (setter) Custom_setlast, |
| "last name", NULL}, |
| {NULL} /* Sentinel */ |
| }; |
| |
| static PyObject * |
| Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored)) |
| { |
| return PyUnicode_FromFormat("%S %S", self->first, self->last); |
| } |
| |
| static PyMethodDef Custom_methods[] = { |
| {"name", (PyCFunction) Custom_name, METH_NOARGS, |
| "Return the name, combining the first and last name" |
| }, |
| {NULL} /* Sentinel */ |
| }; |
| |
| static PyTypeObject CustomType = { |
| PyVarObject_HEAD_INIT(NULL, 0) |
| .tp_name = "custom4.Custom", |
| .tp_doc = "Custom objects", |
| .tp_basicsize = sizeof(CustomObject), |
| .tp_itemsize = 0, |
| .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, |
| .tp_new = Custom_new, |
| .tp_init = (initproc) Custom_init, |
| .tp_dealloc = (destructor) Custom_dealloc, |
| .tp_traverse = (traverseproc) Custom_traverse, |
| .tp_clear = (inquiry) Custom_clear, |
| .tp_members = Custom_members, |
| .tp_methods = Custom_methods, |
| .tp_getset = Custom_getsetters, |
| }; |
| |
| static PyModuleDef custommodule = { |
| PyModuleDef_HEAD_INIT, |
| .m_name = "custom4", |
| .m_doc = "Example module that creates an extension type.", |
| .m_size = -1, |
| }; |
| |
| PyMODINIT_FUNC |
| PyInit_custom4(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; |
| } |