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 void
Custom_dealloc(CustomObject * self)12 Custom_dealloc(CustomObject *self)
13 {
14     Py_XDECREF(self->first);
15     Py_XDECREF(self->last);
16     Py_TYPE(self)->tp_free((PyObject *) self);
17 }
18 
19 static PyObject *
Custom_new(PyTypeObject * type,PyObject * args,PyObject * kwds)20 Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
21 {
22     CustomObject *self;
23     self = (CustomObject *) type->tp_alloc(type, 0);
24     if (self != NULL) {
25         self->first = PyUnicode_FromString("");
26         if (self->first == NULL) {
27             Py_DECREF(self);
28             return NULL;
29         }
30         self->last = PyUnicode_FromString("");
31         if (self->last == NULL) {
32             Py_DECREF(self);
33             return NULL;
34         }
35         self->number = 0;
36     }
37     return (PyObject *) self;
38 }
39 
40 static int
Custom_init(CustomObject * self,PyObject * args,PyObject * kwds)41 Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
42 {
43     static char *kwlist[] = {"first", "last", "number", NULL};
44     PyObject *first = NULL, *last = NULL, *tmp;
45 
46     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
47                                      &first, &last,
48                                      &self->number))
49         return -1;
50 
51     if (first) {
52         tmp = self->first;
53         Py_INCREF(first);
54         self->first = first;
55         Py_XDECREF(tmp);
56     }
57     if (last) {
58         tmp = self->last;
59         Py_INCREF(last);
60         self->last = last;
61         Py_XDECREF(tmp);
62     }
63     return 0;
64 }
65 
66 static PyMemberDef Custom_members[] = {
67     {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0,
68      "first name"},
69     {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0,
70      "last name"},
71     {"number", T_INT, offsetof(CustomObject, number), 0,
72      "custom number"},
73     {NULL}  /* Sentinel */
74 };
75 
76 static PyObject *
Custom_name(CustomObject * self,PyObject * Py_UNUSED (ignored))77 Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
78 {
79     if (self->first == NULL) {
80         PyErr_SetString(PyExc_AttributeError, "first");
81         return NULL;
82     }
83     if (self->last == NULL) {
84         PyErr_SetString(PyExc_AttributeError, "last");
85         return NULL;
86     }
87     return PyUnicode_FromFormat("%S %S", self->first, self->last);
88 }
89 
90 static PyMethodDef Custom_methods[] = {
91     {"name", (PyCFunction) Custom_name, METH_NOARGS,
92      "Return the name, combining the first and last name"
93     },
94     {NULL}  /* Sentinel */
95 };
96 
97 static PyTypeObject CustomType = {
98     PyVarObject_HEAD_INIT(NULL, 0)
99     .tp_name = "custom2.Custom",
100     .tp_doc = "Custom objects",
101     .tp_basicsize = sizeof(CustomObject),
102     .tp_itemsize = 0,
103     .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
104     .tp_new = Custom_new,
105     .tp_init = (initproc) Custom_init,
106     .tp_dealloc = (destructor) Custom_dealloc,
107     .tp_members = Custom_members,
108     .tp_methods = Custom_methods,
109 };
110 
111 static PyModuleDef custommodule = {
112     PyModuleDef_HEAD_INIT,
113     .m_name = "custom2",
114     .m_doc = "Example module that creates an extension type.",
115     .m_size = -1,
116 };
117 
118 PyMODINIT_FUNC
PyInit_custom2(void)119 PyInit_custom2(void)
120 {
121     PyObject *m;
122     if (PyType_Ready(&CustomType) < 0)
123         return NULL;
124 
125     m = PyModule_Create(&custommodule);
126     if (m == NULL)
127         return NULL;
128 
129     Py_INCREF(&CustomType);
130     PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
131     return m;
132 }
133