4

I am a beginner Python programmer, working on embedding some Python code into C++ DLL. Could not make PyObject_CallMethod work, it returned Null every time I called the Python 3.6 class method. Created a small example to illustrate the issue, please see the comments in the code. Would appreciate some guidance on what I am doing wrong.

    #include "stdafx.h"

using namespace std;

int TestBasicStats()
{
    _putenv_s("PYTHONPATH", ".");

    Py_Initialize();

    PyObject* module = PyImport_ImportModule("BasicStats");
    assert(module != NULL); // Returned non-null object

    PyObject* MyPyClass = PyObject_GetAttrString(module, "BasicStats");
    assert(MyPyClass != NULL);// Returned non-null object

    PyObject* myClassInstance = PyInstanceMethod_New(MyPyClass);
    assert(myClassInstance != NULL);// Returned non-null object

    PyObject* result = PyObject_CallMethod(myClassInstance, "AddItem", "(i)", 1);
    assert(result != NULL); // Failed - returned NULL

    result = PyObject_CallMethod(myClassInstance, "AddItem", "(i)", 2);
    assert(result != NULL); // Failed - returned NULL

    result = PyObject_CallMethod(myClassInstance, "get_Max", NULL);
    assert(result != NULL); // Failed - returned NULL

    printf("Min = %ld\n", PyLong_AsLong(result));
    printf("Min = %f\n", PyFloat_AsDouble(result));

    Py_Finalize();

    return 0;
}


int main()
{
    TestBasicStats();

    return 0;
}

The Python class called is as follows:

class BasicStats:
def __init__(self):
    self._m_min = self._m_max = self._m_sum = self._m_sumSqr = 0
    self._m_count = 0
    self.Reset()

def Reset(self):
    self._m_min = float("inf")
    self._m_max = float("-inf")
    self._m_sum = self._m_sumSqr = 0
    self._m_count = 0

def AddItem(self, value):
    self._m_count += 1
    if self._m_max < value:
        self._m_max = value

def get_Max(self):
    return self._m_max

Max = property(fget=get_Max)

2 Answers 2

2

The bit I don't understand here is the PyInstanceMethod_New() call. I really am not sure what it is doing at all, as I have never used this in any of my code. The PyObject you get from the PyObject_GetAttrString() call should be the type object, and as such, a callable, which can be called to create a new object of that type. So to create a BasicStats object, I would call the type object as a function:

PyObject* myClassInstance = PyObject_CallFunctionObjArgs(myPyClass, NULL);
Sign up to request clarification or add additional context in comments.

1 Comment

The documentation says that PyInstanceMethod_New creates a function - which explains why it doesn't work, it's not actually creating an instance.
0

I believe that

PyObject* myClassInstance = PyInstanceMethod_New(MyPyClass);

really should be

// should call __init__. assumes __init__() has arity of 1
// otherwise you will have to marshall correct arguments
PyObject* myClassInstance = PyObject_CallObject(MyPyClass, 0);

Comments

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.