Extension Module for Python 3.6 +
MRAB
python at mrabarnett.plus.com
Fri Mar 1 15:41:38 EST 2019
On 2019-03-01 01:19, Anthony Flury via Python-list wrote:
> In my brave and noble quest to get to grips with the CAPI - I am trying
> to write a C extension module which provides a new class
>
> The exact details are not important, but what is important is that
> instances of my new class are imutable, and therefore from time to time,
> my extension module needs to build a new instance of my extension class.
>
> The documentation is pretty sparse here, and suggests using PyObject_New
> & PyObject_Init but gives no examples.
>
> An internet search suggests using PyObject_CallObject in some way - but
> the examples here are call backs to Python functions.
>
> What is the canonical way to create New Instances of the Extension Type
> from within the Extension Module - even if someone can point me to a
> working example that would be great.
>
> Another option would be to call the extension class new and init
> functions directly - is there a reason that is not allowed ?
>
> PS - I think I also need to use Py_BuildValue to 'encapsulate' the
> initial arguments for the new instance - or could I just build a 'blank'
> instance and then directly set the fields as neccessary ?
>
Here's an example that exports a 'make' factory function to create a new
instance. Hope it helps:
----8<---- class_example.c ----8<----
#include "Python.h"
#include "structmember.h" /* offsetof */
/* The MyClassObject. */
typedef struct MyClassObject {
PyObject_HEAD
PyObject* weakreflist; /* List of weak references. */
PyObject* value;
} MyClassObject;
/* The MyClass_Type. */
static PyTypeObject MyClass_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"class_example.MyClass",
sizeof(MyClassObject)
};
/* Makes an instance with the given value. */
Py_LOCAL_INLINE(PyObject*) myclass_make(PyObject* self_, PyObject* args,
PyObject* kwargs) {
PyObject* value;
MyClassObject* instance;
static char* kwlist[] = { "value", NULL };
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", kwlist, &value))
return NULL;
instance = PyObject_New(MyClassObject, &MyClass_Type);
if (!instance)
return NULL;
instance->value = value;
Py_INCREF(instance->value);
return (PyObject*)instance;
}
/* Deallocates a MyClassObject. */
static void myclass_dealloc(PyObject* self_) {
MyClassObject* self;
self = (MyClassObject*)self_;
Py_DECREF(self->value);
PyObject_DEL(self);
}
/* The documentation of a MyClassObject. */
PyDoc_STRVAR(myclass_doc, "MyClass object");
/* The methods of a MyClassObject. */
static PyMethodDef myclass_methods[] = {
/* The instance methods here. */
{NULL, NULL}
};
/* The members of a MyClassObject. */
static PyMemberDef myclass_members[] = {
{"value", T_OBJECT, offsetof(MyClassObject, value), READONLY,
"The stored value."},
{NULL} /* Sentinel */
};
PyDoc_STRVAR(myclass_make_doc,
"make(value) --> MyClassObject.\n"
" Makes a MyClass object.");
/* The table of the module's functions. */
static PyMethodDef functions[] = {
{ "make", (PyCFunction)myclass_make, METH_VARARGS | METH_KEYWORDS,
myclass_make_doc },
{ NULL, NULL }
};
/* The module definition. */
static struct PyModuleDef class_example_module = {
PyModuleDef_HEAD_INIT,
"class_example",
NULL,
-1,
functions,
NULL,
NULL,
NULL,
NULL
};
/* Initialises the module. */
PyMODINIT_FUNC PyInit_class_example(void) {
PyObject* this_module;
/* Initialise the MyClass_Type. */
MyClass_Type.tp_dealloc = myclass_dealloc;
MyClass_Type.tp_flags = Py_TPFLAGS_DEFAULT;
MyClass_Type.tp_doc = myclass_doc;
MyClass_Type.tp_weaklistoffset = offsetof(MyClassObject, weakreflist);
MyClass_Type.tp_methods = myclass_methods;
MyClass_Type.tp_members = myclass_members;
if (PyType_Ready(&MyClass_Type) < 0)
return NULL;
/* Create the module. */
this_module = PyModule_Create(&class_example_module);
if (!this_module)
return NULL;
/* This makes MyClass visible, but won't let you create an
instance. Useful
* with Python's isinstance function.
*/
if (PyModule_AddObject(this_module, "MyClass",
(PyObject*)&MyClass_Type) != 0)
return NULL;
return this_module;
}
----8<---- test_example.py ----8<----
#!python3.7
# -*- coding: utf-8 -*-
import class_example
from class_example import make
instance = make(0)
print(instance)
print(instance.value)
# Cannot change the attribute:
#instance.value = 1
More information about the Python-list
mailing list