2

I'm a bit confused. I'm trying to do some C++ and Python integration, but it's less than straightforward. I'm not using Boost, because I couldn't get Boost::Python to compile properly. But that's another story.

Currently, here's what I'm doing in C++:

//set everything up
PyObject* py_main_module = PyImport_AddModule("__main__");
PyObject* py_global_dict = PyModule_GetDict(py_main_module);
PyObject* py_local_dict = PyDict_New();
PyObject* py_return_value;

PyRun_SimpleString(data.c_str()); //runs Python code, which defines functions

//call a function defined by the python code
py_return_value = PyRun_String("test()", Py_single_input, py_global_dict, py_local_dict);

//attempt to check the type of the returned value
if(py_return_value != NULL) {
    //this is the problem: all of these print 0
    cout << PyList_Check(py_return_value) << endl;
    cout << PySet_Check(py_return_value) << endl;
    cout << PyFloat_Check(py_return_value) << endl;
} else {
    cout << "IT WAS NULL?!" << endl;
}

The Python program (input to the C++ program as the string named "data"):

def test():
    derp = 1.234
    #derp = [1, 2, 3, 4]
    #derp = set([1, 2, 3, 4])
    return derp

Now, the problem is that the type checks aren't working. They all return 0, regardless of whether the Python function is returning a float, a list, or a set. What am I doing wrong?

Bonus points if anyone can tell me why the call to PyRun_String prints the returned value in the console. It's really annoying.

Will Tice
  • 434
  • 4
  • 17

2 Answers2

3

From the docs:

int Py_eval_input

The start symbol from the Python grammar for isolated expressions; for use with Py_CompileString().

int Py_file_input

The start symbol from the Python grammar for sequences of statements as read from a file or other source; for use with Py_CompileString(). This is the symbol to use when compiling arbitrarily long Python source code.

int Py_single_input

The start symbol from the Python grammar for a single statement; for use with Py_CompileString(). This is the symbol used for the interactive interpreter loop.

Py_single_input evaluates the string as a statement. Statements don't inherently return anything, so you'll get None back from PyRun_String. Use Py_eval_input instead to evaluate the string as an expression and get a result.

nneonneo
  • 171,345
  • 36
  • 312
  • 383
  • Thank you! That does indeed solve both of my problems. What is the difference between evaluating as a statement or as an expression, besides the return value? Or is that the only difference? – Will Tice Feb 26 '13 at 15:08
  • Expressions can produce values; examples are `x - 1`, `foo(blah)`, `lambda x:y`. Statements are usual lines of code in Python, and include things like assignments `x = 1` and function definitions. An expression by itself can be a statement, but not all statements can be treated as expressions. (You can think of an expression as anything you could pass to a function). – nneonneo Feb 26 '13 at 17:50
2

Changing Py_single_input to Py_eval_input seems to resolve both issues.

The former treats the string as part of the interpreter loop, while the latter evaluates a single expression and gives you an object back. (I'm not sure what the return value means in the former case, but it's not the value of the expression.)

EDIT: Just tested it, and as per nneonneo's answer below, the result with Py_single_input is indeed Py_None.

Stephen Lin
  • 5,470
  • 26
  • 48