Search code examples
pythonc++python-3.xvisual-studio-2019python-c-api

PyRun_String returns a NoneType object


I'm writing a base64 function in c++.I want to use python to do the encode and returns the result to my c++ program.Here is my code:

string EncodeBase64(string str)
{
    Py_Initialize();
    PyObject* ret1 = NULL;
    PyObject* ret2 = NULL;
    PyObject* main = PyImport_AddModule("__main__");
    PyObject* _g = PyModule_GetDict(main);
    PyObject* _l = PyDict_New();
    string py = "str(base64.b64encode('" + str + "'.encode('utf-8')), 'utf-8')";
    string pyb = "base64.b64encode('" + str + "'.encode('utf-8'))";
    char* rec = new char[8192];
    cout << "Request 1: " << py << endl;
    cout << "Request 2: " << pyb << endl;
    PyRun_SimpleString("import base64");
    ret1 = PyRun_String(py.c_str(), Py_file_input, _g, _l);
    main = PyImport_AddModule("__main__");
    _g = PyModule_GetDict(main);
    _l = PyDict_New();
    ret2 = PyRun_String(pyb.c_str(), Py_file_input, _g, _l);
    if (!ret1)
    {
        cout << "Can not get return value 1." << endl;
    }
    else
    {
        cout << "Type of Return Value 1: " << ret1->ob_type->tp_name << endl;
    }
    if (!ret2)
    {
        cout << "Can not get return value 1." << endl;
    }
    else
    {
        cout << "Type of Return Value 2: " << ret1->ob_type->tp_name << endl;
    }
    Py_Finalize();
    return "";
}

I input a string "123456",and the program outputs this:

Request 1: str(base64.b64encode('123456'.encode('utf-8')), 'utf-8')
Request 2: base64.b64encode('123456'.encode('utf-8'))
Type of Return Value 1: NoneType
Type of Return Value 2: NoneType

I tried to input the request strings to python,is runs fine.The result is as follows:

C:\Users\15819>python
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import base64
>>> str(base64.b64encode('123456'.encode('utf-8')), 'utf-8')
'MTIzNDU2'
>>> base64.b64encode('123456'.encode('utf-8'))
b'MTIzNDU2'

I want to know why does the return value of PyRun_String is NoneType and how to make it return the right value. My envrionment information:

System: Windows 10 1909 x64
C++IDE: Visual Studio 2019 Professional
Python version: 3.7.4
Project Config: Release X64

Solution

  • Passing a start parameter of Py_file_input is similar in effect to passing 'exec' to the compile built-in; it means run it as if it were a complete module (think of it like asking for the "result" of import modulename; there is no "result").

    Only expressions evaluate to a non-trivial/non-None result, not modules or statements, so for any start parameter but Py_eval_input (equivalent to 'eval' mode for compile), the result will always be None (it's only None because they need to return something to distinguish between NULL for failure and something else for success, and the eval mode necessitates a PyObject* return rather than a boolean). If you want to evaluate an expression and get the result, you must use Py_eval_input for your start parameter.