I am calling a Python Function from a C++ function like below.
void CPPFunction(PyObject* pValue)
{
...
pValue = PyObject_CallObject(PythonFunction, NULL);
...
}
int main()
{
PyObject *pValue = NULL;
CPPFunction(PValue);
int result_of_python_function = Pylong_aslong(PValue);
}
I would like to access the return value of python function outside the CPPFunction. since scope of PObject* returned by PyObject_CallObject is within CPPFunction, how to access the value outside CPPFunction?
Return it from the function like you would anywhere else.
PyObject* CPPFunction()
{
// ...
PyObject* pValue = PyObject_CallObject(PythonFunction, NULL);
// ...
return pValue;
}
int main()
{
PyObject *value = CPPFunction();
int result_of_python_function = Pylong_aslong(value);
}
make following changes and u can access the return value of python function outside the CPPFunction.Hope this helps:
PyObject* CPPFunction(PyObject* PythonFunction) // changes return type from void to PyObject and pass PythonFunction to be called
{
pValue = PyObject_CallObject(PythonFunction, NULL);
return pValue;
}
int main()
{
PyObject *pValue = NULL;
pValue = CPPFunction(PythonFunction); // assign return value from CPPFunction call to PyObject pointer pvalue
long int result_of_python_function = Pylong_aslong(PValue);// data type changed from int to long int
cout << result_of_python_function << endl; // just printing the python result
}
Related
As the title suggests, I'm trying to create a bunch of attributes but the code is getting repetitive and messy. I want to use the closure argument to make the code more compact.
According to the C API reference, the closure is a function pointer that provides additional information for getters/setters. I have not been able to find an example of it in use.
This is how I am currently using it:
static void closure_1() {};
static void closure_2() {};
...
static PyObject *
FOO_getter(FOO* self, void *closure) {
if (closure == &closure_1) {
return self->bar_1;
} else if (closure == &closure_2) {
return self->bar_2;
}
}
static int
FOO_setter(FOO* self, PyObject *value, void *closure) {
if (closure == &closure_1) {
if (somehow value is invalid) {
PyErr_SetString(PyExc_ValueError, "invalid value for bar_1.");
return -1;
}
} else if (closure == closure_2) {
if (somehow value is invalid) {
PyErr_SetString(PyExc_ValueError, "invalid value for bar_2.");
return -1;
}
}
return 0;
}
static PyGetSetDef FOO_getsetters[] = {
{"bar_1", (getter) FOO_getter, (setter) FOO_setter, "bar_1 attribute", closure_1},
{"bar_2", (getter) FOO_getter, (setter) FOO_setter, "bar_2 attribute", closure_2},
{NULL} /* Sentinel */
};
...
It works the way I want it to, but it looks more like a hack than something "pythonic". Is there a better way to handle this? e.g. call the closure in some way.
I guess this "closure" is used to pass an extra context to Foo_getter. It should be something that simplifies accessing members of Foo. Documentation it likely wrong. It should be "optional pointer", not "optional function pointer".
Consider passing offsets of the members. Offsets to struct members can be easily obtained with standard offsetof macro defined in stddef.h. It is a small unsigned integer that will fit to void* type.
static PyGetSetDef FOO_getsetters[] = {
{"bar_1", (getter) FOO_getter, (setter) FOO_setter, "bar_1 attribute", (void*)offsetof(FOO, bar_1)},
{"bar_2", (getter) FOO_getter, (setter) FOO_setter, "bar_2 attribute", (void*)offsetof(FOO, bar_2)},
{NULL} /* Sentinel */
};
Now the getter could be:
static PyObject *
FOO_getter(FOO* self, void *closure) {
// pointer to location where the FOO's member is stored
char *memb_ptr = (char*)self + (size_t)closure;
// cast to `PyObject**` because `mem_ptr` points to location where a pointer to `PyObject` is stored
return *(PyObject**)mem_ptr;
}
Use similar schema for the setter.
Despite the documentation, I'm assuming the closure can be any pointer you want. So how about passing an "object", seeing as C doesn't support closures (short of literally generating functions at run-time).
In an object, we can store the offset of the member in FOO, and a pointer to an attribute-specific validator.
typedef int (*Validator)(FOO *, const struct Attribute *, void *);
typedef struct Attribute {
const char *name;
size_t offset;
Validator validator;
} Attribute;
static PyObject **resolve_offset(FOO *self, const Attribute *attr) {
return (PyObject **)( ( (char *)self ) + attr->offset );
}
static PyObject *FOO_getter(FOO *self, void *_attr) {
const Attribute *attr = (const Attribute *)_attr;
return *resolve_offset(self, attr);
}
static int FOO_setter(FOO *self, PyObject *val, void *_attr) {
const Attribute *attr = (const Attribute *)_attr;
if (attr->validator(self, attr, val)) {
*resolve_offset(self, attr) = val;
return 0;
} else {
// Building the string to include attr->name is left to you.
PyErr_SetString(PyExc_ValueError, "invalid value.");
return -1;
}
}
static int FOO_bar_1_validator(FOO *self, const Attribute *attr, void *val) { ... }
static int FOO_bar_2_validator(FOO *self, const Attribute *attr, void *val) { ... }
#define ATTRIBUTE(name) \
static Attribute FOO_ ## name ## attr = { \
#name, \
offsetof(FOO, name), \
FOO_ ## name ## _validator \
};
ATTRIBUTE(bar_1);
ATTRIBUTE(bar_2);
#define PY_ATTR_DEF(name) { \
#name, \
(getter)FOO_getter, \
(setter)FOO_setter, \
#name " attribute", \
&(FOO_ ## name ## attr) \
}
static PyGetSetDef FOO_getsetters[] = {
PY_ATTR_DEF(bar_1),
PY_ATTR_DEF(bar_2),
{ NULL }
};
I originally wrote:
resolve_offset surely relies on undefined behaviour, but it should work fine. The alternative would be to have three functions in our attribute object (get, validate, set) instead of one, but that defies the point of the question.
But #tstanisl points out that it looks like it isn't UB. Awesome!
I want to call the Python function in C++ using python.h but there are some problems.
Here is my Python function sample
def function1(tuple1, tuple2, string1, string2 ,string3, double1, string4 = ""):
...
and the C++ sample
double function_adapter(const vector<double> &vec1, const vector<double> &vec2, const string &string1, const string &string2, const string &string3, const double double1, const string &string4)
{
Py_Initial();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append(\"./\")");
PyObject *pModule, *pFunc, *pRes;
pModule = PyImport_Import(PyString_FromString("PythonFile"));
pFunc = PyObject_GetAttrString(pModule, "function1");
PyObject *pArgs = PyTuple_New(7);
PyObject *pVec1 = PyTuple_New(vec1.size());
for(size_t i = 0; i < vec1.size(); ++i) {
PyTuple_SetItem(pVec1, i, Py_BuildValue("f", vec1[i]));
}
PyObject *pVec2 = PyTuple_New(vec2.size());
for(size_t i = 0; i < vec2.size(); ++i) {
PyTuple_SetItem(pVec2, i, Py_BuildValue("f", vec2[i]));
}
PyObject *pString1 = Py_BuildValue("s", string1);
PyObject *pString2 = Py_BuildValue("s", string2);
PyObject *pString3 = Py_BuildValue("s", string3);
PyObject *pDouble1 = Py_BuildValue("f", double1);
PyObject *pString4 = Py_BuildValue("s", string4);
PyTuple_SetItem(pArgs, 0, pVec1);
PyTuple_SetItem(pArgs, 1, pVec2);
PyTuple_SetItem(pArgs, 2, pString1);
PyTuple_SetItem(pArgs, 3, pString2);
PyTuple_SetItem(pArgs, 4, pString3);
PyTuple_SetItem(pArgs, 5, pDouble1);
PyTuple_SetItem(pArgs, 6, pString4);
pRes = PyObject_CallObject(pFunc, pArgs);
if(pRes == NULL) {
return -2;
}
int res = PyLong_AsLong(pRes);
Py_DecRef(pModule);
.
.
.
Py_Finalize();
return res;
}
But the pRes returns NULL. And the PyObject_CallObject is just like a blackbox, I can't step in to look how it works.
So I want to ask that is there anything wrong in my code?
And the arguments preparation is right or not? (There are few examples in this case on the internet.)
A CPython API function that returns NULL means that an error has occurred. You can use the PyErr_* set of API functions to query this exception.
For debugging, the most useful is probably PyErr_Print(), which will just print the exception and stack trace (if any) to stderr.
Make sure to double check that pModule and pFunc are not NULL. The exception may have occurred when trying to import the module or get the function from the module. CPython does not raise exceptions, it just returns NULL on an error. So checking the return value of C-API functions is important.
Suppose for the purpose of this discussion, I have a function like this:
PyObject* tuple_from_dict(PyObject* ftype, PyObject* factory, PyObject* values) {
PyObject* ttype = PyTuple_GetItem(factory, 1);
PyObject* fmapping = PyTuple_GetItem(factory, 2);
PyObject* key;
PyObject* value;
Py_ssize_t pos = 0;
Py_ssize_t arg_len = 0;
Py_ssize_t field;
PyObject* result;
if (PyDict_Size(fmapping) == 0) {
result = PyObject_Call(ttype, PyTuple_New(0), NULL);
Py_INCREF(result);
return result;
}
while (PyDict_Next(fmapping, &pos, &key, &value)) {
field = PyLong_AsSsize_t(value);
if (field > arg_len) {
arg_len = field;
}
}
PyObject* args = PyTuple_New(arg_len + 1);
pos = 0;
while (pos < arg_len + 1) {
Py_INCREF(Py_None);
PyTuple_SetItem(args, pos, Py_None);
pos++;
}
pos = 0;
while (PyDict_Next(values, &pos, &key, &value)) {
field = PyLong_AsSsize_t(PyDict_GetItem(fmapping, key));
PyTuple_SetItem(args, field, value);
}
result = PyObject_Call(ttype, args, NULL);
if (result) {
Py_INCREF(result);
}
return result;
}
It doesn't matter what exactly does it do, the important point is that it calls PyObject_Call(...), which I suspect to be slow. But, the slowness we are talking about would not be noticeable on per call basis (the code overall does couple thousands calls per 1/100 of second). So... I need an aggregate, or some way of measuring the time with very high precision (so, clock_t doesn't seem like it's a good level of precision).
It's OK if the solution will work only on Linux. It is also OK if I could somehow slow everything down, but get a more precise measurement of the timing in question.
Is clock_gettime() useful? It is POSIX interface to high resolution timer. This post provides this example usage.
#include <iostream>
#include <time.h>
using namespace std;
timespec diff(timespec start, timespec end);
int main()
{
timespec time1, time2;
int temp;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
for (int i = 0; i< 242000000; i++)
temp+=temp;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time2);
cout<<diff(time1,time2).tv_sec<<":"<<diff(time1,time2).tv_nsec<<endl;
return 0;
}
timespec diff(timespec start, timespec end)
{
timespec temp;
if ((end.tv_nsec-start.tv_nsec)<0) {
temp.tv_sec = end.tv_sec-start.tv_sec-1;
temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
} else {
temp.tv_sec = end.tv_sec-start.tv_sec;
temp.tv_nsec = end.tv_nsec-start.tv_nsec;
}
return temp;
}
i wrote the C code as follow:
int main(int argc, char** argv)
{
PyObject *mod, *name, *func;
Py_Initialize();
mod = PyImport_ImportModule("perf_tester");
if(!mod)
{
printf("cannot find perf_tester.py");
getchar();
return -1;
}
name = PyObject_GetAttrString(mod, "CheckSharpness");
if(!name)
{
printf("can not find CheckSharpness");
getchar();
return -1;
}
func = PyObject_GetAttrString(name,"F");
if(!func)
{
printf("can not find function");
getchar();
return -1;
}
Py_Finalize();
system("pause");
return 0;
}
except for func, i could find mod and name.
and the partial of the perf_tester.py as follow:
def CheckSharpness(sample, edges, min_pass_mtf, min_pass_lowest_mtf,
use_50p, mtf_sample_count, mtf_patch_width,
mtf_crop_ratio=_MTF_DEFAULT_CROP_RATIO,
n_thread=1):
mtfs = [mtf_calculator.Compute(sample, line_start[t], line_end[t],
mtf_patch_width, mtf_crop_ratio,
use_50p)[0] for t in perm]
F = open("data.txt","w")
F.write(str(mtfs))
F.close()
what could I do?
F is a local variable, it's not a member of CheckSharpness. It does not exist when CheckSharpness is not currently running, and each invocation of CheckSharpness has its own copy. There's no way to access this from outside.
I am trying to figure out how in C extension modules to have a variable (and maybe) quite large number of arguments to a function.
Reading about PyArg_ParseTuple it seems you have to know how many to accept, some mandatory and some optional but all with their own variable. I was hoping PyArg_UnpackTuple would be able to handle this but it seems to just give me bus errors when I try and use it in what appears to be the wrong way.
As an example take the following python code that one might want to make into an extension module (in C).
def hypot(*vals):
if len(vals) !=1 :
return math.sqrt(sum((v ** 2 for v in vals)))
else:
return math.sqrt(sum((v ** 2 for v in vals[0])))
This can be called with any number of arguments or iterated over, hypot(3,4,5), hypot([3,4,5]), and hypot(*[3,4,5]) all give the same answer.
The start of my C function looks like this
static PyObject *hypot_tb(PyObject *self, PyObject *args) {
// lots of code
// PyArg_ParseTuple or PyArg_UnpackTuple
}
Many thinks to yasar11732. Here for the next guy is a fully working extension module (_toolboxmodule.c) that simply takes in any number or integer arguments and returns a list made up of those arguments (with a poor name). A toy but illustrates what needed to be done.
#include <Python.h>
int ParseArguments(long arr[],Py_ssize_t size, PyObject *args) {
/* Get arbitrary number of positive numbers from Py_Tuple */
Py_ssize_t i;
PyObject *temp_p, *temp_p2;
for (i=0;i<size;i++) {
temp_p = PyTuple_GetItem(args,i);
if(temp_p == NULL) {return NULL;}
/* Check if temp_p is numeric */
if (PyNumber_Check(temp_p) != 1) {
PyErr_SetString(PyExc_TypeError,"Non-numeric argument.");
return NULL;
}
/* Convert number to python long and than C unsigned long */
temp_p2 = PyNumber_Long(temp_p);
arr[i] = PyLong_AsUnsignedLong(temp_p2);
Py_DECREF(temp_p2);
}
return 1;
}
static PyObject *hypot_tb(PyObject *self, PyObject *args)
{
Py_ssize_t TupleSize = PyTuple_Size(args);
long *nums = malloc(TupleSize * sizeof(unsigned long));
PyObject *list_out;
int i;
if(!TupleSize) {
if(!PyErr_Occurred())
PyErr_SetString(PyExc_TypeError,"You must supply at least one argument.");
return NULL;
}
if (!(ParseArguments(nums, TupleSize, args)) {
free(nums);
return NULL;
}
list_out = PyList_New(TupleSize);
for(i=0;i<TupleSize;i++)
PyList_SET_ITEM(list_out, i, PyInt_FromLong(nums[i]));
free(nums);
return (PyObject *)list_out;
}
static PyMethodDef toolbox_methods[] = {
{ "hypot", (PyCFunction)hypot_tb, METH_VARARGS,
"Add docs here\n"},
// NULL terminate Python looking at the object
{ NULL, NULL, 0, NULL }
};
PyMODINIT_FUNC init_toolbox(void) {
Py_InitModule3("_toolbox", toolbox_methods,
"toolbox module");
}
In python then it is:
>>> import _toolbox
>>> _toolbox.hypot(*range(4, 10))
[4, 5, 6, 7, 8, 9]
I had used something like this earlier. It could be a bad code as I am not an experienced C coder, but it worked for me. The idea is, *args is just a Python tuple, and you can do anything that you could do with a Python tuple. You can check http://docs.python.org/c-api/tuple.html .
int
ParseArguments(unsigned long arr[],Py_ssize_t size, PyObject *args) {
/* Get arbitrary number of positive numbers from Py_Tuple */
Py_ssize_t i;
PyObject *temp_p, *temp_p2;
for (i=0;i<size;i++) {
temp_p = PyTuple_GetItem(args,i);
if(temp_p == NULL) {return NULL;}
/* Check if temp_p is numeric */
if (PyNumber_Check(temp_p) != 1) {
PyErr_SetString(PyExc_TypeError,"Non-numeric argument.");
return NULL;
}
/* Convert number to python long and than C unsigned long */
temp_p2 = PyNumber_Long(temp_p);
arr[i] = PyLong_AsUnsignedLong(temp_p2);
Py_DECREF(temp_p2);
if (arr[i] == 0) {
PyErr_SetString(PyExc_ValueError,"Zero doesn't allowed as argument.");
return NULL;
}
if (PyErr_Occurred()) {return NULL; }
}
return 1;
}
I was calling this function like this:
static PyObject *
function_name_was_here(PyObject *self, PyObject *args)
{
Py_ssize_t TupleSize = PyTuple_Size(args);
Py_ssize_t i;
struct bigcouples *temp = malloc(sizeof(struct bigcouples));
unsigned long current;
if(!TupleSize) {
if(!PyErr_Occurred())
PyErr_SetString(PyExc_TypeError,"You must supply at least one argument.");
free(temp);
return NULL;
}
unsigned long *nums = malloc(TupleSize * sizeof(unsigned long));
if(!ParseArguments(nums, TupleSize, args)){
/* Make a cleanup and than return null*/
return null;
}