Search code examples
c++python-3.xpython-c-apipython-embedding

PyObject_CallMethod: call static member function from c++


I've embedded Python (3.6) code into my C++ application successfully. I use the Python/C API to call methods from this library. An overview of the python module is as follows:

class MyClass(object):
    def __init__(args: str) -> None:
        ...
        return
    
    def callable_method(*args) -> Tuple:
        ...
        return some_tuple

    @staticmethod()
    def create_from_cli_args(argv: List[str]) -> 'MyClass':
        ...
        return MyClass(parsed_args)

The static method is a new addition to my code to move exception logic from the __init__ function to another function and yield an object. The C++ code to construct an object before was as follows:

PyObject *module_name = PyUnicode_FromString("module_path.my_class");

// Load the module object
PyObject *module = PyImport_Import(module_name);
if(module == nullptr) return;
Py_DECREF(module_name);

// Get callable list from module
PyObject *dict = PyModule_GetDict(module);
if(dict == nullptr) return;
Py_DECREF(module);

// Builds the name of a callable class
PyObject *my_class = PyDict_GetItemString(dict, "MyClass");
if(python_class == nullptr) return;

// Check if python class is callable
if(!PyCallable_Check(my_class)) return;

// Populate args for class instantiation
PyObject *py_args = PyTuple_New(1);
PyTuple_SetItem(py_args, 0, PyUnicode_FromString("Initialize_Configs"));

// Construct object
PyObject *my_class_obj = PyObject_CallObject(my_class, py_args);
if(my_class_obj == nullptr) return;

The above code snippet works, however, with the addition of the static method I'm trying to use to create an object of my_class, I'm unable to figure out how to call a static method of a class. I've tried using PyObject *my_class = PyDict_GetItemString(dict, "MyClass.create_my_class"); as well as PyObject_CallMethod(my_class, "create_my_class", kargs, kwargs) but that doesn't work either. I'd appreciate any help.


Solution

  • As the person in the comments suggested, I was incorrectly calling the static method. The solution is:

    ...
    if(!PyCallable_Check(my_class)) return;
    
    // A static method can be called the same as a normal method in python.
    PyObject *my_class_object = PyObject_CallMethod(my_class, "create_from_cli_args", "s", "--cli_args");
    
    if(!my_class_object) return;