0

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.

3
  • "The above code snippet works" - it shouldn't. You're using PyObject_CallMethod wrong. You didn't even specify a method name, and its signature in general is nothing like how you called it. Commented Feb 5, 2022 at 2:26
  • Check the docs, give it the right arguments, and you should be able to use it to call your static method. Commented Feb 5, 2022 at 2:27
  • You need the calls to Py_DECREF before the early returns - otherwise you leak an object if the calls fail. Given you are coding in C++, I would actually wrap the PyObject* in a RAII class. Commented Dec 16, 2022 at 8:06

1 Answer 1

1

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;
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you! This (implicitly) answers my question of "does CallMethod handle the difference between instance methods, class methods, and static methods - and if not, how do I handle them".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.