pythonc++tuplespython-embeddingpyobject

Create Python Constructor with parameter from C++, PyObject


I have a python class A like this.

class A: 
   def __init__(self, name): 
       self.name = name

   def print_lastname(self, lastname): 
       print(lastname)

I have to call this code like this.

import B
a = B.A("hello")
a.print_lastname("John")

Currently, I need to use this A class from my C++ code. I have got this far.

Py_Initialize(); 
string hello = "hello"; 
PyObject *module, *attr, *arg; 
module = PyObject_ImportModule("B"); // import B
attr = PyObject_GetAttrString(module, "A"); // get A from B
arg = PyString_FromString(hello.c_str()); 
instance = PyInstance_New(attr, arg, NULL); // trying to get instance of A with parameter "hello"
Py_Finalize(); 

But I am getting error

Exception TypeError: 'argument list must be tuple' in module 'threading' from '/usr/lib64/python2.7/threading.pyc'

How can I achieve from import statement to a.print_name("John") from C++? Any help is appreciated.


Solution

  • I'm going to rewrite the Python class slightly, just so it uses both the argument and member variable.

    # B.py - test module
    class A:
        def __init__(self, name):
            self.name = name
    
        def print_message(self, message):
            print message + ' ' + self.name
    

    As for the C++ part, almost everything looks okay. The error you're getting is because the argument to PyInstance_New should be a tuple. There are multiple ways to call functions or methods. Here is a complete example using one of them:

    // test.c - test embedding.
    void error_abort(void)
    {
        PyErr_Print();
        exit(EXIT_FAILURE);
    }
    
    int main(int argc, char* argv[])
    {
        PyObject* temp, * args, * attr, * instance;
    
        Py_Initialize();
        if (!(temp = PyString_FromString("John")))
            error_abort();
        if (!(args = PyTuple_Pack(1, temp)))
            error_abort();
        Py_DECREF(temp);
    
        if (!(temp = PyImport_ImportModule("B")))
            error_abort();
        if (!(attr = PyObject_GetAttrString(temp, "A")))
            error_abort();
        Py_DECREF(temp);
    
        if (!(instance = PyInstance_New(attr, args, NULL)))
            error_abort();
        if (!PyObject_CallMethod(instance, "print_message", "s", "Hello"))
            error_abort();
    
        Py_DECREF(args);
        Py_DECREF(attr);
        Py_DECREF(instance);
        Py_Finalize();
        return 0;
    }
    

    For more information see Python pure-embedding.