Previously I have created some Python classes using C API. When I'm going to build the old project with Python 3+ it gives following compile error
PyClass_New was not declared in this scope Py_InitModule was not declared in this scope
What are the equivalents?
PyObject *pClassDic = PyDict_New();
PyObject *pClassName = PyBytes_FromString("MyClass");
PyObject *pClass = PyClass_New(NULL, pClassDic, pClassName);
If you don't want to go through the hassle of setting up your object and type structs, you should be able to create a new class by calling Python's type(name, bases, dict)
from C:
PyObject *pClassName = PyBytes_FromString("MyClass");
PyObject *pClassBases = PyTuple_New(0); // An empty tuple for bases is equivalent to `(object,)`
PyObject *pClassDic = PyDict_New();
// pClass = type(pClassName, pClassBases, pClassDic)
PyObject *pClass = PyObject_CallFunctionObjArgs(PyType_Type, pClassName, pClassBases, pClassDic, NULL);
Py_CLEAR(pClassName);
Py_CLEAR(pClassBases);
Py_CLEAR(pClassDic);
to complete the answer from 'cpburnz', here's a function that creates a class object and add methods :
PyObject *createClassObject(const char *name, PyMethodDef methods[])
{
PyObject *pClassName = PyUnicode_FromString(name);
PyObject *pClassBases = PyTuple_New(0); // An empty tuple for bases is equivalent to `(object,)`
PyObject *pClassDic = PyDict_New();
PyMethodDef *def;
// add methods to class
for (def = methods; def->ml_name != NULL; def++)
{
printf(" add method %s\n", def->ml_name);
PyObject *func = PyCFunction_New(def, NULL);
PyObject *method = PyInstanceMethod_New(func);
PyDict_SetItemString(pClassDic, def->ml_name, method);
Py_DECREF(func);
Py_DECREF(method);
}
// pClass = type(pClassName, pClassBases, pClassDic)
PyObject *pClass = PyObject_CallFunctionObjArgs((PyObject *)&PyType_Type, pClassName, pClassBases, pClassDic, NULL);
Py_DECREF(pClassName);
Py_DECREF(pClassBases);
Py_DECREF(pClassDic);
return pClass;
}
Then, you can use it like this :
static PyMethodDef foo_Methods[] =
{
{ "__init__", fooInit, METH_VARARGS, "doc" },
{ "do_something", fooDoSomething, METH_VARARGS, "doc" },
{ 0, 0 },
};
PyObject * fooClass = createClassObject("fooClass", foo_Methods);
PyModule_AddObject(module, "foo", fooClass );
PyModule_AddObject is requested to make the "foo" class visible to python code.
Note : as suggested by 'RomanK', using PyTypeObject is a good (and probably better) alternative.
EDIT : I confirm it's much better and easy to use PyTypeObject directly, fill the structure and call PyModule_AddObject() to make the new type available to Python. It's more flexible, offers more flexibility and it's the official way. As mentionned by Cilyan, everything is explained here : https://docs.python.org/3.3/extending/newtypes.html?highlight=pytypeobject
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With