I have an embedded python interpreter in my program. I'd like to export a module with values defined in my program and be able to change them from a python script. e.g.
in c:
int x = 1;
in python:
import embedded
embedded.x = 2
in c:
printf("%d",x);
output:
2
Is this possible or do I have to export functions to change anything in c?
There's no need to export functions, but the easiest way to do this would be to use PyModule_GetDict() with PyDict_GetItemString() to get the value assigned to the x attribute.
If you don't want to actively check the value of a PyObject in your C code, I think you need to export functions to modify the representation in C. I'm no expert, but I don't think there's an automatic mapping.
Related
What is the meaning of set.constant ?
I have a program that i need to write in python without using creating a new class. Is there an equivalent of it in python or numpy specifically ?
Python doesnt use constants.
To use a variable outside the current scope you can use:
global var
var =
I have a small python module I have created with the Python C API which I call mycore.
I have also created some utility scripts in Python which are related.
How can I put both in the same module namespace? I know I can call Python code from my C code but surely there is an easier way to do that.
Thanks
The obvious way is by making mycore a package. Create a mycore/__init__.py that imports both the C part, typically named something like _mycore, and the Python part:
from _mycore import *
from _mycorepy import *
In the same directory you'd have a _mycore.so and _mycorepy.py.
Another way to mix Python and C code is by invoking PyRun_String on the embedded Python. This might be what you mean by I know I can call Python code from my C code..., but just in case, here is a simple example with the potentially tricky refcounting details:
PyObject *get_factory()
{
PyObject *g, *runret, *factory;
// prepare a dictionary for the module to run in
g = Py_BuildValue("{s:O}", "__builtins__", PyEval_GetBuiltins());
if (!g)
return NULL;
// run Python code in the dictionary -- the code may import modules, etc.
runret = PyRun_String("\
def factory():\n\
return 42\n", Py_file_input, g, NULL);
Py_XDECREF(runret);
if (!runret) {
Py_DECREF(g);
return NULL;
}
Py_DECREF(runret);
// pick the stuff you care about from the dictionary and return it
factory = PyDict_GetItemString(g, "factory");
Py_INCREF(factory);
Py_DECREF(g);
return factory;
}
OK, this worked for me. My circumstances may be different. My C module was built internally and provided to my embedded Python with a call to PyImport_AppendInittab().
But I still had some accompanying Python code that I wanted associated with the same namespace.
So I got it working by naming my C code _mygadget and the Python file mygadget.py. For the first line of mygadget.py I wrote:
from _mygadget import *
This seems to work. I don't know what would happen if I had a Python method and C call with the same name. I am avoiding that at present.
I am really curious as to how Python's interpreter makes an attribute x out of a method x through x=property(x). If I could take a look at the C code, I would feel much better.
The type is defined in the descrobject.c file.
You can locate Python types like these by first looking for the function name in bltinmodule.c; in this case the following line defines the property() function:
SETBUILTIN("property", &PyProperty_Type);
then grep for the PyProperty_Type definition in the Objects subdirectory.
I've initialized the Python environment by
Py_Initialize();
I have no external Python module imported into the environment and everything works well. But when I need to pass a C string into this environment, I am lost...
I was thinking to add a function in the environment to assign the variable like the following code do.
char *str;
str="\
def assign_var(str):\
global string\
string = str";
PyRun_SimpleString(str);
And then call this function in C and pass the converted C string as the arguments.
I don't think all I mentioned above is a good way solve the problem...
How can I make this work?
Solution:
Finally, here's the solution with Peter Mortensen's help. (Thanks Peter Mortensen!)
As the python environment I've initialized is a pure empty environment(without any imported modules). I use
py_main = PyImport_AddModule("__main__");
to get a hook to the main environment. and then call
PyModule_AddStringConstant(py_main, "string_name", str);
to bring the C string into the python environment.
To verify everything is done, just try:
PyRun_SimpleString("print dir()");
PyRun_SimpleString("print string_name");
and you'll see you "string_name" string appears in the dir() list and make it print by python!
This should do what you want:
char *cStr = "Some text here.";
PyObject *pyStr = Py_BuildValue("s", cStr);
http://docs.python.org/c-api/arg.html#Py_BuildValue
Of course if you're using Python 3 (or use it in the future), there may be situations where you'd want to use "y" instead of "s" and get a bytes object rather than a str.
UPDATE: Woops, I forgot the even easier way of doing it.
PyObject *pyStr = PyString_FromString(cStr);
http://docs.python.org/c-api/string.html#PyString_FromString
(It'd be PyBytes_FromString() in Python 3.)
You might want to take a look at http://docs.python.org/extending/embedding.html for some more information.
Here's something else you might want to try. See
http://docs.python.org/c-api/module.html#PyModule_AddObject
Or possibly
http://docs.python.org/c-api/module.html#PyModule_AddStringConstant
With the former it'd be something like
errorcheck = PyModule_AddObject(embmodule, "str", pyStr);
And with the latter, something like
errorcheck = PyModule_AddStringConstant(embmodule, "str", cStr);
I have some global variables in a Python script. Some functions in that script call into C - is it possible to set one of those variables while in C and if so, how?
I appreciate that this isn't a very nice design in the first place, but I need to make a small change to existing code, I don't want to embark on major refactoring of existing scripts.
I'm not a python guru, but I found this question interesting so I googled around. This was the first hit on "python embedding API" - does it help?
If the attributes belong to the global
scope of a module, then you can use
"PyImport_AddModule" to get a handle
to the module object. For example, if
you wanted to get the value of an
integer in the main module named
"foobar", you would do the following:
PyObject *m = PyImport_AddModule("__main__");
PyObject *v = PyObject_GetAttrString(m,"foobar");
int foobar = PyInt_AsLong(v);
Py_DECREF(v);
For anyone coming here from Google, here's the direct method:
PyObject* PyEval_GetGlobals()
https://docs.python.org/2/c-api/reflection.html
https://docs.python.org/3/c-api/reflection.html
The return value is accessed as a dictionary.
I recommend using pyrex to make an extension module you can store the values in in python, and cdef a bunch of functions which can be called from C to return the values there.
Otherwise, much depends on the type of values you're trying to transmit.
Are you willing to modify the API a little bit?
You can make the C function return the new value for the global, and then call it like this:
my_global = my_c_func(...)
If you're using Robin or the Python C API directly, you can pass the globals dictionary as an additional parameter and modify it
If your global is always in the same module, Sherm's solution looks great