Commit 1d80a561 authored by Antoine Pitrou's avatar Antoine Pitrou Committed by GitHub

bpo-33201: Modernize "Extension types" doc (GH-6337)

* bpo-33201: Modernize "Extension types" doc
* Split tutorial and other topics
* Some small fixes
* Address some review comments
* Rename noddy* to custom* and shoddy to sublist
* Fix markup
parent b405752d
...@@ -26,9 +26,11 @@ Recommended third party tools ...@@ -26,9 +26,11 @@ Recommended third party tools
============================= =============================
This guide only covers the basic tools for creating extensions provided This guide only covers the basic tools for creating extensions provided
as part of this version of CPython. Third party tools like Cython, as part of this version of CPython. Third party tools like
``cffi``, SWIG and Numba offer both simpler and more sophisticated `Cython <http://cython.org/>`_, `cffi <https://cffi.readthedocs.io>`_,
approaches to creating C and C++ extensions for Python. `SWIG <http://www.swig.org>`_ and `Numba <https://numba.pydata.org/>`_
offer both simpler and more sophisticated approaches to creating C and C++
extensions for Python.
.. seealso:: .. seealso::
...@@ -52,6 +54,7 @@ C extensions. ...@@ -52,6 +54,7 @@ C extensions.
:numbered: :numbered:
extending.rst extending.rst
newtypes_tutorial.rst
newtypes.rst newtypes.rst
building.rst building.rst
windows.rst windows.rst
......
This diff is collapsed.
This diff is collapsed.
#include <Python.h>
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
} CustomObject;
static PyTypeObject CustomType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "custom.Custom",
.tp_doc = "Custom objects",
.tp_basicsize = sizeof(CustomObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = PyType_GenericNew,
};
static PyModuleDef custommodule = {
PyModuleDef_HEAD_INIT,
.m_name = "custom",
.m_doc = "Example module that creates an extension type.",
.m_size = -1,
};
PyMODINIT_FUNC
PyInit_custom(void)
{
PyObject *m;
if (PyType_Ready(&CustomType) < 0)
return NULL;
m = PyModule_Create(&custommodule);
if (m == NULL)
return NULL;
Py_INCREF(&CustomType);
PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
return m;
}
...@@ -6,49 +6,44 @@ typedef struct { ...@@ -6,49 +6,44 @@ typedef struct {
PyObject *first; /* first name */ PyObject *first; /* first name */
PyObject *last; /* last name */ PyObject *last; /* last name */
int number; int number;
} Noddy; } CustomObject;
static void static void
Noddy_dealloc(Noddy* self) Custom_dealloc(CustomObject *self)
{ {
Py_XDECREF(self->first); Py_XDECREF(self->first);
Py_XDECREF(self->last); Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject *) self);
} }
static PyObject * static PyObject *
Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
Noddy *self; CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
self = (Noddy *)type->tp_alloc(type, 0);
if (self != NULL) { if (self != NULL) {
self->first = PyUnicode_FromString(""); self->first = PyUnicode_FromString("");
if (self->first == NULL) { if (self->first == NULL) {
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
} }
self->last = PyUnicode_FromString(""); self->last = PyUnicode_FromString("");
if (self->last == NULL) { if (self->last == NULL) {
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
} }
self->number = 0; self->number = 0;
} }
return (PyObject *) self;
return (PyObject *)self;
} }
static int static int
Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{ {
PyObject *first=NULL, *last=NULL, *tmp;
static char *kwlist[] = {"first", "last", "number", NULL}; static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last, &first, &last,
&self->number)) &self->number))
return -1; return -1;
...@@ -59,114 +54,79 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) ...@@ -59,114 +54,79 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
self->first = first; self->first = first;
Py_XDECREF(tmp); Py_XDECREF(tmp);
} }
if (last) { if (last) {
tmp = self->last; tmp = self->last;
Py_INCREF(last); Py_INCREF(last);
self->last = last; self->last = last;
Py_XDECREF(tmp); Py_XDECREF(tmp);
} }
return 0; return 0;
} }
static PyMemberDef Custom_members[] = {
static PyMemberDef Noddy_members[] = { {"first", T_OBJECT_EX, offsetof(CustomObject, first), 0,
{"first", T_OBJECT_EX, offsetof(Noddy, first), 0,
"first name"}, "first name"},
{"last", T_OBJECT_EX, offsetof(Noddy, last), 0, {"last", T_OBJECT_EX, offsetof(CustomObject, last), 0,
"last name"}, "last name"},
{"number", T_INT, offsetof(Noddy, number), 0, {"number", T_INT, offsetof(CustomObject, number), 0,
"noddy number"}, "custom number"},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
static PyObject * static PyObject *
Noddy_name(Noddy* self) Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
{ {
if (self->first == NULL) { if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first"); PyErr_SetString(PyExc_AttributeError, "first");
return NULL; return NULL;
} }
if (self->last == NULL) { if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last"); PyErr_SetString(PyExc_AttributeError, "last");
return NULL; return NULL;
} }
return PyUnicode_FromFormat("%S %S", self->first, self->last); return PyUnicode_FromFormat("%S %S", self->first, self->last);
} }
static PyMethodDef Noddy_methods[] = { static PyMethodDef Custom_methods[] = {
{"name", (PyCFunction)Noddy_name, METH_NOARGS, {"name", (PyCFunction) Custom_name, METH_NOARGS,
"Return the name, combining the first and last name" "Return the name, combining the first and last name"
}, },
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
static PyTypeObject NoddyType = { static PyTypeObject CustomType = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"noddy.Noddy", /* tp_name */ .tp_name = "custom2.Custom",
sizeof(Noddy), /* tp_basicsize */ .tp_doc = "Custom objects",
0, /* tp_itemsize */ .tp_basicsize = sizeof(CustomObject),
(destructor)Noddy_dealloc, /* tp_dealloc */ .tp_itemsize = 0,
0, /* tp_print */ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0, /* tp_getattr */ .tp_new = Custom_new,
0, /* tp_setattr */ .tp_init = (initproc) Custom_init,
0, /* tp_reserved */ .tp_dealloc = (destructor) Custom_dealloc,
0, /* tp_repr */ .tp_members = Custom_members,
0, /* tp_as_number */ .tp_methods = Custom_methods,
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
"Noddy objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Noddy_methods, /* tp_methods */
Noddy_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Noddy_init, /* tp_init */
0, /* tp_alloc */
Noddy_new, /* tp_new */
}; };
static PyModuleDef noddy2module = { static PyModuleDef custommodule = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
"noddy2", .m_name = "custom2",
"Example module that creates an extension type.", .m_doc = "Example module that creates an extension type.",
-1, .m_size = -1,
NULL, NULL, NULL, NULL, NULL
}; };
PyMODINIT_FUNC PyMODINIT_FUNC
PyInit_noddy2(void) PyInit_custom2(void)
{ {
PyObject* m; PyObject *m;
if (PyType_Ready(&CustomType) < 0)
if (PyType_Ready(&NoddyType) < 0)
return NULL; return NULL;
m = PyModule_Create(&noddy2module); m = PyModule_Create(&custommodule);
if (m == NULL) if (m == NULL)
return NULL; return NULL;
Py_INCREF(&NoddyType); Py_INCREF(&CustomType);
PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
return m; return m;
} }
...@@ -3,52 +3,47 @@ ...@@ -3,52 +3,47 @@
typedef struct { typedef struct {
PyObject_HEAD PyObject_HEAD
PyObject *first; PyObject *first; /* first name */
PyObject *last; PyObject *last; /* last name */
int number; int number;
} Noddy; } CustomObject;
static void static void
Noddy_dealloc(Noddy* self) Custom_dealloc(CustomObject *self)
{ {
Py_XDECREF(self->first); Py_XDECREF(self->first);
Py_XDECREF(self->last); Py_XDECREF(self->last);
Py_TYPE(self)->tp_free((PyObject*)self); Py_TYPE(self)->tp_free((PyObject *) self);
} }
static PyObject * static PyObject *
Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds) Custom_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{ {
Noddy *self; CustomObject *self;
self = (CustomObject *) type->tp_alloc(type, 0);
self = (Noddy *)type->tp_alloc(type, 0);
if (self != NULL) { if (self != NULL) {
self->first = PyUnicode_FromString(""); self->first = PyUnicode_FromString("");
if (self->first == NULL) { if (self->first == NULL) {
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
} }
self->last = PyUnicode_FromString(""); self->last = PyUnicode_FromString("");
if (self->last == NULL) { if (self->last == NULL) {
Py_DECREF(self); Py_DECREF(self);
return NULL; return NULL;
} }
self->number = 0; self->number = 0;
} }
return (PyObject *) self;
return (PyObject *)self;
} }
static int static int
Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) Custom_init(CustomObject *self, PyObject *args, PyObject *kwds)
{ {
PyObject *first=NULL, *last=NULL, *tmp;
static char *kwlist[] = {"first", "last", "number", NULL}; static char *kwlist[] = {"first", "last", "number", NULL};
PyObject *first = NULL, *last = NULL, *tmp;
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|SSi", kwlist, if (!PyArg_ParseTupleAndKeywords(args, kwds, "|UUi", kwlist,
&first, &last, &first, &last,
&self->number)) &self->number))
return -1; return -1;
...@@ -59,167 +54,130 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds) ...@@ -59,167 +54,130 @@ Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
self->first = first; self->first = first;
Py_DECREF(tmp); Py_DECREF(tmp);
} }
if (last) { if (last) {
tmp = self->last; tmp = self->last;
Py_INCREF(last); Py_INCREF(last);
self->last = last; self->last = last;
Py_DECREF(tmp); Py_DECREF(tmp);
} }
return 0; return 0;
} }
static PyMemberDef Noddy_members[] = { static PyMemberDef Custom_members[] = {
{"number", T_INT, offsetof(Noddy, number), 0, {"number", T_INT, offsetof(CustomObject, number), 0,
"noddy number"}, "custom number"},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
static PyObject * static PyObject *
Noddy_getfirst(Noddy *self, void *closure) Custom_getfirst(CustomObject *self, void *closure)
{ {
Py_INCREF(self->first); Py_INCREF(self->first);
return self->first; return self->first;
} }
static int static int
Noddy_setfirst(Noddy *self, PyObject *value, void *closure) Custom_setfirst(CustomObject *self, PyObject *value, void *closure)
{ {
PyObject *tmp;
if (value == NULL) { if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute"); PyErr_SetString(PyExc_TypeError, "Cannot delete the first attribute");
return -1; return -1;
} }
if (!PyUnicode_Check(value)) {
if (! PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"The first attribute value must be a string"); "The first attribute value must be a string");
return -1; return -1;
} }
tmp = self->first;
Py_DECREF(self->first);
Py_INCREF(value); Py_INCREF(value);
self->first = value; self->first = value;
Py_DECREF(tmp);
return 0; return 0;
} }
static PyObject * static PyObject *
Noddy_getlast(Noddy *self, void *closure) Custom_getlast(CustomObject *self, void *closure)
{ {
Py_INCREF(self->last); Py_INCREF(self->last);
return self->last; return self->last;
} }
static int static int
Noddy_setlast(Noddy *self, PyObject *value, void *closure) Custom_setlast(CustomObject *self, PyObject *value, void *closure)
{ {
PyObject *tmp;
if (value == NULL) { if (value == NULL) {
PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute"); PyErr_SetString(PyExc_TypeError, "Cannot delete the last attribute");
return -1; return -1;
} }
if (!PyUnicode_Check(value)) {
if (! PyUnicode_Check(value)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"The last attribute value must be a string"); "The last attribute value must be a string");
return -1; return -1;
} }
tmp = self->last;
Py_DECREF(self->last);
Py_INCREF(value); Py_INCREF(value);
self->last = value; self->last = value;
Py_DECREF(tmp);
return 0; return 0;
} }
static PyGetSetDef Noddy_getseters[] = { static PyGetSetDef Custom_getsetters[] = {
{"first", {"first", (getter) Custom_getfirst, (setter) Custom_setfirst,
(getter)Noddy_getfirst, (setter)Noddy_setfirst, "first name", NULL},
"first name", {"last", (getter) Custom_getlast, (setter) Custom_setlast,
NULL}, "last name", NULL},
{"last",
(getter)Noddy_getlast, (setter)Noddy_setlast,
"last name",
NULL},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
static PyObject * static PyObject *
Noddy_name(Noddy* self) Custom_name(CustomObject *self, PyObject *Py_UNUSED(ignored))
{ {
return PyUnicode_FromFormat("%S %S", self->first, self->last); return PyUnicode_FromFormat("%S %S", self->first, self->last);
} }
static PyMethodDef Noddy_methods[] = { static PyMethodDef Custom_methods[] = {
{"name", (PyCFunction)Noddy_name, METH_NOARGS, {"name", (PyCFunction) Custom_name, METH_NOARGS,
"Return the name, combining the first and last name" "Return the name, combining the first and last name"
}, },
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
static PyTypeObject NoddyType = { static PyTypeObject CustomType = {
PyVarObject_HEAD_INIT(NULL, 0) PyVarObject_HEAD_INIT(NULL, 0)
"noddy.Noddy", /* tp_name */ .tp_name = "custom3.Custom",
sizeof(Noddy), /* tp_basicsize */ .tp_doc = "Custom objects",
0, /* tp_itemsize */ .tp_basicsize = sizeof(CustomObject),
(destructor)Noddy_dealloc, /* tp_dealloc */ .tp_itemsize = 0,
0, /* tp_print */ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
0, /* tp_getattr */ .tp_new = Custom_new,
0, /* tp_setattr */ .tp_init = (initproc) Custom_init,
0, /* tp_reserved */ .tp_dealloc = (destructor) Custom_dealloc,
0, /* tp_repr */ .tp_members = Custom_members,
0, /* tp_as_number */ .tp_methods = Custom_methods,
0, /* tp_as_sequence */ .tp_getset = Custom_getsetters,
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
"Noddy objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Noddy_methods, /* tp_methods */
Noddy_members, /* tp_members */
Noddy_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Noddy_init, /* tp_init */
0, /* tp_alloc */
Noddy_new, /* tp_new */
}; };
static PyModuleDef noddy3module = { static PyModuleDef custommodule = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
"noddy3", .m_name = "custom3",
"Example module that creates an extension type.", .m_doc = "Example module that creates an extension type.",
-1, .m_size = -1,
NULL, NULL, NULL, NULL, NULL
}; };
PyMODINIT_FUNC PyMODINIT_FUNC
PyInit_noddy3(void) PyInit_custom3(void)
{ {
PyObject* m; PyObject *m;
if (PyType_Ready(&CustomType) < 0)
if (PyType_Ready(&NoddyType) < 0)
return NULL; return NULL;
m = PyModule_Create(&noddy3module); m = PyModule_Create(&custommodule);
if (m == NULL) if (m == NULL)
return NULL; return NULL;
Py_INCREF(&NoddyType); Py_INCREF(&CustomType);
PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType); PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
return m; return m;
} }
#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);
PyModule_AddObject(m, "Custom", (PyObject *) &CustomType);
return m;
}
#include <Python.h>
typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
} noddy_NoddyObject;
static PyTypeObject noddy_NoddyType = {
PyVarObject_HEAD_INIT(NULL, 0)
"noddy.Noddy", /* tp_name */
sizeof(noddy_NoddyObject), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"Noddy objects", /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
PyType_GenericNew, /* tp_new */
};
static PyModuleDef noddymodule = {
PyModuleDef_HEAD_INIT,
"noddy",
"Example module that creates an extension type.",
-1,
NULL, NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC
PyInit_noddy(void)
{
PyObject* m;
if (PyType_Ready(&noddy_NoddyType) < 0)
return NULL;
m = PyModule_Create(&noddymodule);
if (m == NULL)
return NULL;
Py_INCREF(&noddy_NoddyType);
PyModule_AddObject(m, "Noddy", (PyObject *)&noddy_NoddyType);
return m;
}
#include <Python.h>
#include "structmember.h"
typedef struct {
PyObject_HEAD
PyObject *first;
PyObject *last;
int number;
} Noddy;
static int
Noddy_traverse(Noddy *self, visitproc visit, void *arg)
{
int vret;
if (self->first) {
vret = visit(self->first, arg);
if (vret != 0)
return vret;
}
if (self->last) {
vret = visit(self->last, arg);
if (vret != 0)
return vret;
}
return 0;
}
static int
Noddy_clear(Noddy *self)
{
PyObject *tmp;
tmp = self->first;
self->first = NULL;
Py_XDECREF(tmp);
tmp = self->last;
self->last = NULL;
Py_XDECREF(tmp);
return 0;
}
static void
Noddy_dealloc(Noddy* self)
{
PyObject_GC_UnTrack(self);
Noddy_clear(self);
Py_TYPE(self)->tp_free((PyObject*)self);
}
static PyObject *
Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
Noddy *self;
self = (Noddy *)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
Noddy_init(Noddy *self, PyObject *args, PyObject *kwds)
{
PyObject *first=NULL, *last=NULL, *tmp;
static char *kwlist[] = {"first", "last", "number", NULL};
if (! PyArg_ParseTupleAndKeywords(args, kwds, "|OOi", kwlist,
&first, &last,
&self->number))
return -1;
if (first) {
tmp = self->first;
Py_INCREF(first);
self->first = first;
Py_XDECREF(tmp);
}
if (last) {
tmp = self->last;
Py_INCREF(last);
self->last = last;
Py_XDECREF(tmp);
}
return 0;
}
static PyMemberDef Noddy_members[] = {
{"first", T_OBJECT_EX, offsetof(Noddy, first), 0,
"first name"},
{"last", T_OBJECT_EX, offsetof(Noddy, last), 0,
"last name"},
{"number", T_INT, offsetof(Noddy, number), 0,
"noddy number"},
{NULL} /* Sentinel */
};
static PyObject *
Noddy_name(Noddy* self)
{
if (self->first == NULL) {
PyErr_SetString(PyExc_AttributeError, "first");
return NULL;
}
if (self->last == NULL) {
PyErr_SetString(PyExc_AttributeError, "last");
return NULL;
}
return PyUnicode_FromFormat("%S %S", self->first, self->last);
}
static PyMethodDef Noddy_methods[] = {
{"name", (PyCFunction)Noddy_name, METH_NOARGS,
"Return the name, combining the first and last name"
},
{NULL} /* Sentinel */
};
static PyTypeObject NoddyType = {
PyVarObject_HEAD_INIT(NULL, 0)
"noddy.Noddy", /* tp_name */
sizeof(Noddy), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)Noddy_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC, /* tp_flags */
"Noddy objects", /* tp_doc */
(traverseproc)Noddy_traverse, /* tp_traverse */
(inquiry)Noddy_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Noddy_methods, /* tp_methods */
Noddy_members, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Noddy_init, /* tp_init */
0, /* tp_alloc */
Noddy_new, /* tp_new */
};
static PyModuleDef noddy4module = {
PyModuleDef_HEAD_INIT,
"noddy4",
"Example module that creates an extension type.",
-1,
NULL, NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC
PyInit_noddy4(void)
{
PyObject* m;
if (PyType_Ready(&NoddyType) < 0)
return NULL;
m = PyModule_Create(&noddy4module);
if (m == NULL)
return NULL;
Py_INCREF(&NoddyType);
PyModule_AddObject(m, "Noddy", (PyObject *)&NoddyType);
return m;
}
#include <Python.h>
typedef struct {
PyListObject list;
int state;
} Shoddy;
static PyObject *
Shoddy_increment(Shoddy *self, PyObject *unused)
{
self->state++;
return PyLong_FromLong(self->state);
}
static PyMethodDef Shoddy_methods[] = {
{"increment", (PyCFunction)Shoddy_increment, METH_NOARGS,
PyDoc_STR("increment state counter")},
{NULL},
};
static int
Shoddy_init(Shoddy *self, PyObject *args, PyObject *kwds)
{
if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
static PyTypeObject ShoddyType = {
PyVarObject_HEAD_INIT(NULL, 0)
"shoddy.Shoddy", /* tp_name */
sizeof(Shoddy), /* tp_basicsize */
0, /* tp_itemsize */
0, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE, /* tp_flags */
0, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
Shoddy_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Shoddy_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};
static PyModuleDef shoddymodule = {
PyModuleDef_HEAD_INIT,
"shoddy",
"Shoddy module",
-1,
NULL, NULL, NULL, NULL, NULL
};
PyMODINIT_FUNC
PyInit_shoddy(void)
{
PyObject *m;
ShoddyType.tp_base = &PyList_Type;
if (PyType_Ready(&ShoddyType) < 0)
return NULL;
m = PyModule_Create(&shoddymodule);
if (m == NULL)
return NULL;
Py_INCREF(&ShoddyType);
PyModule_AddObject(m, "Shoddy", (PyObject *) &ShoddyType);
return m;
}
#include <Python.h>
typedef struct {
PyListObject list;
int state;
} SubListObject;
static PyObject *
SubList_increment(SubListObject *self, PyObject *unused)
{
self->state++;
return PyLong_FromLong(self->state);
}
static PyMethodDef SubList_methods[] = {
{"increment", (PyCFunction) SubList_increment, METH_NOARGS,
PyDoc_STR("increment state counter")},
{NULL},
};
static int
SubList_init(SubListObject *self, PyObject *args, PyObject *kwds)
{
if (PyList_Type.tp_init((PyObject *) self, args, kwds) < 0)
return -1;
self->state = 0;
return 0;
}
static PyTypeObject SubListType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "sublist.SubList",
.tp_doc = "SubList objects",
.tp_basicsize = sizeof(SubListObject),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
.tp_init = (initproc) SubList_init,
.tp_methods = SubList_methods,
};
static PyModuleDef sublistmodule = {
PyModuleDef_HEAD_INIT,
.m_name = "sublist",
.m_doc = "Example module that creates an extension type.",
.m_size = -1,
};
PyMODINIT_FUNC
PyInit_sublist(void)
{
PyObject *m;
SubListType.tp_base = &PyList_Type;
if (PyType_Ready(&SubListType) < 0)
return NULL;
m = PyModule_Create(&sublistmodule);
if (m == NULL)
return NULL;
Py_INCREF(&SubListType);
PyModule_AddObject(m, "SubList", (PyObject *) &SubListType);
return m;
}
"""Test module for the noddy examples """Test module for the custom examples
Noddy 1: Custom 1:
>>> import noddy >>> import custom
>>> n1 = noddy.Noddy() >>> c1 = custom.Custom()
>>> n2 = noddy.Noddy() >>> c2 = custom.Custom()
>>> del n1 >>> del c1
>>> del n2 >>> del c2
Noddy 2 Custom 2
>>> import noddy2 >>> import custom2
>>> n1 = noddy2.Noddy('jim', 'fulton', 42) >>> c1 = custom2.Custom('jim', 'fulton', 42)
>>> n1.first >>> c1.first
'jim' 'jim'
>>> n1.last >>> c1.last
'fulton' 'fulton'
>>> n1.number >>> c1.number
42 42
>>> n1.name() >>> c1.name()
'jim fulton' 'jim fulton'
>>> n1.first = 'will' >>> c1.first = 'will'
>>> n1.name() >>> c1.name()
'will fulton' 'will fulton'
>>> n1.last = 'tell' >>> c1.last = 'tell'
>>> n1.name() >>> c1.name()
'will tell' 'will tell'
>>> del n1.first >>> del c1.first
>>> n1.name() >>> c1.name()
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: first AttributeError: first
>>> n1.first >>> c1.first
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: first AttributeError: first
>>> n1.first = 'drew' >>> c1.first = 'drew'
>>> n1.first >>> c1.first
'drew' 'drew'
>>> del n1.number >>> del c1.number
Traceback (most recent call last): Traceback (most recent call last):
... ...
TypeError: can't delete numeric/char attribute TypeError: can't delete numeric/char attribute
>>> n1.number=2 >>> c1.number=2
>>> n1.number >>> c1.number
2 2
>>> n1.first = 42 >>> c1.first = 42
>>> n1.name() >>> c1.name()
'42 tell' '42 tell'
>>> n2 = noddy2.Noddy() >>> c2 = custom2.Custom()
>>> n2.name() >>> c2.name()
' ' ' '
>>> n2.first >>> c2.first
'' ''
>>> n2.last >>> c2.last
'' ''
>>> del n2.first >>> del c2.first
>>> n2.first >>> c2.first
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: first AttributeError: first
>>> n2.first >>> c2.first
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: first AttributeError: first
>>> n2.name() >>> c2.name()
Traceback (most recent call last): Traceback (most recent call last):
File "<stdin>", line 1, in ? File "<stdin>", line 1, in ?
AttributeError: first AttributeError: first
>>> n2.number >>> c2.number
0 0
>>> n3 = noddy2.Noddy('jim', 'fulton', 'waaa') >>> n3 = custom2.Custom('jim', 'fulton', 'waaa')
Traceback (most recent call last): Traceback (most recent call last):
File "<stdin>", line 1, in ? File "<stdin>", line 1, in ?
TypeError: an integer is required TypeError: an integer is required (got type str)
>>> del n1 >>> del c1
>>> del n2 >>> del c2
Noddy 3 Custom 3
>>> import noddy3 >>> import custom3
>>> n1 = noddy3.Noddy('jim', 'fulton', 42) >>> c1 = custom3.Custom('jim', 'fulton', 42)
>>> n1 = noddy3.Noddy('jim', 'fulton', 42) >>> c1 = custom3.Custom('jim', 'fulton', 42)
>>> n1.name() >>> c1.name()
'jim fulton' 'jim fulton'
>>> del n1.first >>> del c1.first
Traceback (most recent call last): Traceback (most recent call last):
File "<stdin>", line 1, in ? File "<stdin>", line 1, in ?
TypeError: Cannot delete the first attribute TypeError: Cannot delete the first attribute
>>> n1.first = 42 >>> c1.first = 42
Traceback (most recent call last): Traceback (most recent call last):
File "<stdin>", line 1, in ? File "<stdin>", line 1, in ?
TypeError: The first attribute value must be a string TypeError: The first attribute value must be a string
>>> n1.first = 'will' >>> c1.first = 'will'
>>> n1.name() >>> c1.name()
'will fulton' 'will fulton'
>>> n2 = noddy3.Noddy() >>> c2 = custom3.Custom()
>>> n2 = noddy3.Noddy() >>> c2 = custom3.Custom()
>>> n2 = noddy3.Noddy() >>> c2 = custom3.Custom()
>>> n3 = noddy3.Noddy('jim', 'fulton', 'waaa') >>> n3 = custom3.Custom('jim', 'fulton', 'waaa')
Traceback (most recent call last): Traceback (most recent call last):
File "<stdin>", line 1, in ? File "<stdin>", line 1, in ?
TypeError: an integer is required TypeError: an integer is required (got type str)
>>> del n1 >>> del c1
>>> del n2 >>> del c2
Noddy 4 Custom 4
>>> import noddy4 >>> import custom4
>>> n1 = noddy4.Noddy('jim', 'fulton', 42) >>> c1 = custom4.Custom('jim', 'fulton', 42)
>>> n1.first >>> c1.first
'jim' 'jim'
>>> n1.last >>> c1.last
'fulton' 'fulton'
>>> n1.number >>> c1.number
42 42
>>> n1.name() >>> c1.name()
'jim fulton' 'jim fulton'
>>> n1.first = 'will' >>> c1.first = 'will'
>>> n1.name() >>> c1.name()
'will fulton' 'will fulton'
>>> n1.last = 'tell' >>> c1.last = 'tell'
>>> n1.name() >>> c1.name()
'will tell' 'will tell'
>>> del n1.first >>> del c1.first
>>> n1.name()
Traceback (most recent call last): Traceback (most recent call last):
... ...
AttributeError: first TypeError: Cannot delete the first attribute
>>> n1.first >>> c1.name()
Traceback (most recent call last): 'will tell'
... >>> c1.first = 'drew'
AttributeError: first >>> c1.first
>>> n1.first = 'drew'
>>> n1.first
'drew' 'drew'
>>> del n1.number >>> del c1.number
Traceback (most recent call last): Traceback (most recent call last):
... ...
TypeError: can't delete numeric/char attribute TypeError: can't delete numeric/char attribute
>>> n1.number=2 >>> c1.number=2
>>> n1.number >>> c1.number
2 2
>>> n1.first = 42 >>> c1.first = 42
>>> n1.name() Traceback (most recent call last):
'42 tell' ...
>>> n2 = noddy4.Noddy() TypeError: The first attribute value must be a string
>>> n2 = noddy4.Noddy() >>> c1.name()
>>> n2 = noddy4.Noddy() 'drew tell'
>>> n2 = noddy4.Noddy() >>> c2 = custom4.Custom()
>>> n2.name() >>> c2 = custom4.Custom()
>>> c2 = custom4.Custom()
>>> c2 = custom4.Custom()
>>> c2.name()
' ' ' '
>>> n2.first >>> c2.first
'' ''
>>> n2.last >>> c2.last
'' ''
>>> del n2.first >>> c2.number
>>> n2.first
Traceback (most recent call last):
...
AttributeError: first
>>> n2.first
Traceback (most recent call last):
...
AttributeError: first
>>> n2.name()
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: first
>>> n2.number
0 0
>>> n3 = noddy4.Noddy('jim', 'fulton', 'waaa') >>> n3 = custom4.Custom('jim', 'fulton', 'waaa')
Traceback (most recent call last): Traceback (most recent call last):
File "<stdin>", line 1, in ? ...
TypeError: an integer is required TypeError: an integer is required (got type str)
Test cyclic gc(?) Test cyclic gc(?)
...@@ -183,15 +170,14 @@ Test cyclic gc(?) ...@@ -183,15 +170,14 @@ Test cyclic gc(?)
>>> import gc >>> import gc
>>> gc.disable() >>> gc.disable()
>>> x = [] >>> class Subclass(custom4.Custom): pass
>>> l = [x] ...
>>> n2.first = l >>> s = Subclass()
>>> n2.first >>> s.cycle = [s]
[[]] >>> s.cycle.append(s.cycle)
>>> l.append(n2) >>> x = object()
>>> del l >>> s.x = x
>>> del n1 >>> del s
>>> del n2
>>> sys.getrefcount(x) >>> sys.getrefcount(x)
3 3
>>> ignore = gc.collect() >>> ignore = gc.collect()
......
Modernize documentation for writing C extension types.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment