How to create an instance of a python class from C++

B

Bill

Hello:

I can't figure out how to create an instance
of a python class from 'C++':

( I am relatively new to Python so excuse some of
the following. )

In a .py file I create an ABC and then specialize it:

from MyMod import *
from abc import ABCMeta, abstractmethod

# Declare an abstract base class.
class Base(metaclass=ABCMeta):
"""Base class."""
@abstractmethod
def description(self):
return "From the base class."

# Declare a class that inerits from the base.
class Derived(Base):
"""Derived class."""
def description(self):
return "From the Derived."

# Register the derived class.
RegisterClass(Derived)

Then from 'C++' (my implementation of RegisterClass)
I try to create an instance

static PyObject *
RegisterClass( PyObject *, PyObject *args ) { // This gets called ok.

PyObject *class_decl;
if( ! PyArg_ParseTuple(args, "O", &class_decl) )
return NULL;
Py_INCREF(class_decl);

PyTypeObject *typ = class_decl->ob_type;

// Tried this.
// PyObject *an = _PyObject_New(class_decl->ob_type); assert(an);
// PyObject *desc = PyObject_CallMethod(an,"description",NULL); assert(desc);

// Tried this.
// PyObject *an = PyType_GenericNew((PyTypeObject *)class_decl->ob_type, NULL, NULL); assert(an);
// assert(class_decl); assert(class_decl->ob_type); assert(class_decl->ob_type->tp_new);

// This returns something.
assert(class_decl); assert(class_decl->ob_type); assert(class_decl->ob_type->tp_new);
PyObject *an_inst = class_decl->ob_type->tp_new(class_decl->ob_type,NULL, NULL); assert(an_inst);
assert(class_decl->ob_type->tp_init);

// This crashes.
int ret = class_decl->ob_type->tp_init(an_inst,NULL, NULL); assert(ret == 0);
// PyObject_CallMethod(an_inst,"__init__",NULL);
// PyObject *an_inst = PyObject_CallMethod(class_decl,"__new__",NULL); assert(an_inst);

// Never get here.
PyObject *desc = PyObject_CallMethod(an_inst,"description",NULL); assert(desc);
char *cp = _PyUnicode_AsString(desc);
cerr << "Description:" << cp << endl;

return PyLong_FromLong(0);
}

static PyMethodDef MyModMethods[] = {
{ "RegisterClass", RegisterClass, METH_VARARGS, "Register class." },
{ NULL, NULL, 0, NULL }
};

static struct PyModuleDef MyModMod = {
PyModuleDef_HEAD_INIT,
"MyMod", // name of module
NULL, // module documentation, may be NULL
-1,
MyModMethods,
NULL,
NULL,
NULL,
NULL
};

PyMODINIT_FUNC
PyInit_MyMod( void ) {
PyObject* m = PyModule_Create(&MyModMod);
if( m == NULL )
return NULL;
return m;
}

int
main( int, char ** ) {

PyImport_AppendInittab( "MyMod", PyInit_MyMod );

Py_Initialize();

const char *file_name = "z.py";
FILE *fp = fopen(file_name,"r");
if( fp ) {
PyRun_SimpleFileExFlags(fp,file_name,1,0);
}

Py_Finalize();

return 0;
}
 
I

Ian Kelly

Hello:

I can't figure out how to create an instance
of a python class from 'C++':

( I am relatively new to Python so excuse some of
the following. )

In a .py file I create an ABC and then specialize it:

Why are you creating an ABC? Most Python classes do not use them.
Maybe you have a reason for it, but it's irrelevant to what you're
currently trying to do.
Then from 'C++' (my implementation of RegisterClass)
I try to create an instance

static PyObject *
RegisterClass( PyObject *, PyObject *args ) { // This gets called ok.

PyObject *class_decl;
if( ! PyArg_ParseTuple(args, "O", &class_decl) )
return NULL;
Py_INCREF(class_decl);

So far, so good. The object that was passed in was the "Derived"
class object. Since you presumably only want class objects to be
passed in, you might want to check that here using PyType_Check.
PyTypeObject *typ = class_decl->ob_type;

Okay, now if class_decl is the class object that was passed in, then
class_decl->ob_type is the *type* of that class object -- the
metaclass, which in this case would be ABCMeta. You probably don't
need this, because you want to instantiate Derived, not ABCMeta.
// Tried this.
// PyObject *an = _PyObject_New(class_decl->ob_type); assert(an);
// PyObject *desc = PyObject_CallMethod(an,"description",NULL); assert(desc);

In Python, you instantiate a class by calling it. You should do the
same in C, using PyObject_CallFunction. But as above, note that you
want to call class_decl, not class_decl->ob_type.

PyObject_New doesn't do any initialization and is, I believe, meant to
be used when implementing types in C.
 
B

Bill

So far, so good. The object that was passed in was the "Derived"
class object. Since you presumably only want class objects to be
passed in, you might want to check that here using PyType_Check.
Yes. Will do.


In Python, you instantiate a class by calling it. You should do the
same in C, using PyObject_CallFunction. But as above, note that you
want to call class_decl, not class_decl->ob_type.

Of course. That works.

Thanks.

Bill
 
G

Grant Edwards

Why are you creating an ABC?

Because it was the first binary computer that did calculations with
electronic switching elements (gates), and it would be really cool to
have one! The ABC also pioneered the use of capciators as regenerative
storage elements (it's how DRAM still works today).

http://en.wikipedia.org/wiki/Atanasoff–Berry_Computer

It predated ENIAC, and it's clear that some of the features of ENIAC
were inspired by the ABC after John Mauchly visited Iowa State and saw
the ABC.
 
G

Grant Edwards

But it was not programmable

True. It had only one program that was hard-wired into it when it was
built as opposed to the external patch-cords and switches that were
used on machines like Colossus and ENIAC to alter the wiring.
 
G

Gene Heskett

True. It had only one program that was hard-wired into it when it was
built as opposed to the external patch-cords and switches that were
used on machines like Colossus and ENIAC to alter the wiring.

What machine was it that had about 12,000 12AU7 vacuum tubes in it for
logic? They had one of those, adapted to read the output of a bed of
photocells installed in a Harris sheet fed press on the SUI campus in the
later 1950's. I saw it running once, grading the test score sheets from
the Iowa Tests that were being used in lieu of the high price per seat S-B
IQ test in the Iowa schools. It was IIRC a somewhat difficult test when
they threw it at me in the 7th grade a decade earlier, they claimed the
test score were interchangeable with the S-B scores, but I somehow managed
a 147 on it at the time.

Cheers, Gene
--
"There are four boxes to be used in defense of liberty:
soap, ballot, jury, and ammo. Please use in that order."
-Ed Howdershelt (Author)
Genes Web page <http://geneslinuxbox.net:6309/gene>

NOTICE: Will pay 100 USD for an HP-4815A defective but
complete probe assembly.
 
B

Barry Scott

Hello:

I can't figure out how to create an instance
of a python class from 'C++':

Why not use pycxx from http://sourceforge.net/projects/cxx/?

This lib does all the heavy lifting for you for both python2 and python3.
Has docs and examples.

Barry
PyCXX maintainer.


( I am relatively new to Python so excuse some of
the following. )

In a .py file I create an ABC and then specialize it:

from MyMod import *
from abc import ABCMeta, abstractmethod

# Declare an abstract base class.
class Base(metaclass=ABCMeta):
"""Base class."""
@abstractmethod
def description(self):
return "From the base class."

# Declare a class that inerits from the base.
class Derived(Base):
"""Derived class."""
def description(self):
return "From the Derived."

# Register the derived class.
RegisterClass(Derived)

Then from 'C++' (my implementation of RegisterClass)
I try to create an instance

static PyObject *
RegisterClass( PyObject *, PyObject *args ) { // This gets called ok.

PyObject *class_decl;
if( ! PyArg_ParseTuple(args, "O", &class_decl) )
return NULL;
Py_INCREF(class_decl);

PyTypeObject *typ = class_decl->ob_type;

// Tried this.
// PyObject *an = _PyObject_New(class_decl->ob_type); assert(an);
// PyObject *desc = PyObject_CallMethod(an,"description",NULL); assert(desc);

// Tried this.
// PyObject *an = PyType_GenericNew((PyTypeObject *)class_decl->ob_type, NULL, NULL); assert(an);
// assert(class_decl); assert(class_decl->ob_type); assert(class_decl->ob_type->tp_new);

// This returns something.
assert(class_decl); assert(class_decl->ob_type); assert(class_decl->ob_type->tp_new);
PyObject *an_inst = class_decl->ob_type->tp_new(class_decl->ob_type,NULL, NULL); assert(an_inst);
assert(class_decl->ob_type->tp_init);

// This crashes.
int ret = class_decl->ob_type->tp_init(an_inst,NULL, NULL); assert(ret == 0);
// PyObject_CallMethod(an_inst,"__init__",NULL);
// PyObject *an_inst = PyObject_CallMethod(class_decl,"__new__",NULL); assert(an_inst);

// Never get here.
PyObject *desc = PyObject_CallMethod(an_inst,"description",NULL); assert(desc);
char *cp = _PyUnicode_AsString(desc);
cerr << "Description:" << cp << endl;

return PyLong_FromLong(0);
}

static PyMethodDef MyModMethods[] = {
{ "RegisterClass", RegisterClass, METH_VARARGS, "Register class." },
{ NULL, NULL, 0, NULL }
};

static struct PyModuleDef MyModMod = {
PyModuleDef_HEAD_INIT,
"MyMod", // name of module
NULL, // module documentation, may be NULL
-1,
MyModMethods,
NULL,
NULL,
NULL,
NULL
};

PyMODINIT_FUNC
PyInit_MyMod( void ) {
PyObject* m = PyModule_Create(&MyModMod);
if( m == NULL )
return NULL;
return m;
}

int
main( int, char ** ) {

PyImport_AppendInittab( "MyMod", PyInit_MyMod );

Py_Initialize();

const char *file_name = "z.py";
FILE *fp = fopen(file_name,"r");
if( fp ) {
PyRun_SimpleFileExFlags(fp,file_name,1,0);
}

Py_Finalize();

return 0;
}
 
S

Stefan Behnel

Barry Scott, 11.03.2014 22:37:
Why not use pycxx from http://sourceforge.net/projects/cxx/?

This lib does all the heavy lifting for you for both python2 and python3.
Has docs and examples.

Yes, tool support definitely helps here. I was going to suggest Cython
(also for obvious reasons), where the code that the OP posted would look
like this:

def RegisterClass(class_decl):
an = type(class_decl)()
print(an.description())
return 0

Clearly substantially simpler than the posted C code (and certainly safer,
faster and more correct) - although that doesn't really help me much with
understanding what the intention of this code is, looks rather weird...

Stefan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top