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
--
https://mail.python.org/mailman/listinfo/python-list