-
Notifications
You must be signed in to change notification settings - Fork 1
How to send more data to python
- To see these techniques in use view Strategy.cc. the pyFunction.
- the first command that must be run before using or calling python Scripts or PyObjects is Py_Initialize(). this function basically creates a python interpreter to run python commands and files
- to run a python command use the following command PyRun_SimpleString("import os"). in this example here we are importing the os library to interpreter.
- this is an example on how you can call on a python file. to check if it has imported you can put pModule in an if statement
//calling on myFile.py
PyObject * pName = PyUnicode_FromString("myFile");
PyObject * pModule = PyImport_Import(pName);
if(pModule)
{
// running the method myFunc in myFile.py
PyObject * pFunc = PyObject_GetAttrString(pModule, "myFunc");
if(pFunc && PyCallable_Check(pFunc))
{
//here we call on the python function and store the output in a PyObject in this example we are sending in a list so we attach an O before world_data
PyObject * pReturn = PyObject_CallFunction(pFunc,"O",world_data);
//here we convert the pyobject to the relevent c++ format
int x = (int) PyLong_AsLong(pReturn);
return x;
}
else
{
cout << "ERROR: function selectSkill()\n"<<endl;
return -1;
}
}
else
{
cout << "ERROR: Module not imported"<<endl;
return -2;
}for info on how to convert c++ to PyObject look here and how to convert from PyObject to c++ you can look here
- an example of converting a c++ data type to a python Object
//converting an integer to a PyObject
int x = 5
PyObject * temp;
temp = Py_BuildValue("i",x);- an example of extracting data from a PyObject
PyObject * objectPy;
//update objectPy
int x = (int) PyLong_AsLong(objectPy);- how to define a python list
int n = 5;
PyObject* pyList = PyList_New(n);- how to get an item from the pyList (get the item at index 0)
PyObject* item = PyList_GetItem(pyList, 0);- how to set an item in a python list
int value = 5;
PyObject * item = Py_BuildValue("i",value);
PyList_SetItem(PyList,0,item);In strategy.cc, there is a method: worldData(), which takes in a series of PyObjects, and returns them as a list. It is this list, world_data, that is passed through to python.
C++ side:
PyObject * world_data = worldData(playerNumPy,playModePy,sidePy,posPy,ballPy, teamPositionsPy, oppPositionsPy ,teamDistToBallPy,OppDistToBallPy);
n = pyFunction(world_data,pos); //This calls on selectSkill() in python, passing it world_data as a parameterPython side:
import Robocup as RC
def selectSkill(world_data): #see how selectSkill() takes in world_data as a parameter
robocup = RC.Robocup(world_data) #see how the Robocup constructor takes in world_data as a parameterworldData()
PyObject * worldData(PyObject * _playerNumber,PyObject * _playMode,PyObject * _side,PyObject * posPy,PyObject * ballPy,PyObject * teamPositionsPy,PyObject * oppPositionsPy,PyObject * teamDistToBallPy,PyObject * OppDistToBallPy){
//this mirrors constructor for Robocup class on python side
PyObject * pyList;
pyList = PyList_New(9);
PyList_SetItem(pyList,0,_playerNumber);
PyList_SetItem(pyList,1,_playMode);
PyList_SetItem(pyList,2,_side);
PyList_SetItem(pyList,3,posPy);
PyList_SetItem(pyList,4,ballPy);
PyList_SetItem(pyList,5,teamPositionsPy);
PyList_SetItem(pyList,6,oppPositionsPy);
PyList_SetItem(pyList,7,teamDistToBallPy);
PyList_SetItem(pyList,8,OppDistToBallPy);
return pyList;Robocup constructor:
class Robocup():
#...
def __init__(self, world_data):
"""
Parameters
----------
world data passed through to selectSkill() - ALTERATION IS NOT RECOMMENDED
This mirrors worldData method on C++ side
"""
#World Model Data:
self.__player_number=world_data[0]
self.__play_mode=world_data[1]
self.__side = world_data[2]
self.__player_pos = world_data[3]
self.__ball_pos = world_data[4]
self.__team_positions = world_data[5]
self.__opponent_positions = world_data[6]
#Wrapped C++ Functions:
self.__team_dist_ball = world_data[7]
self.__opp_dist_ball = world_data[8]As you can see, the constructor for the Robocup class in python clearly mirrors the method for worldData in C++.
If you wish to pass more data through from C++ to python, simply convert that data to a PyObject (as described above) and edit the worldData() method so it accepts another object parameter, and adds it to the world_data list.
You will have to initialise the list to be larger, as well as add the object to the list:
PyObject * worldData(/*...*/, PyObject yourNewObject){ //adding your new object to the parameters for worldData()
pyList = PyList_New(n);//change the n value to match the number of parameters.
// ...
PyList_SetItem(pyList,n,yourNewObject); //adding your new object to the world_data list at index n
return pyList
}Now, make the relevant changes to the Robocup constructor on the python side. This will mirror the worldData() method in C++.
class Robocup():
#...
def __init__(self, world_data):
#...
self.__your_new_object = world_data[n] #we recommend making this object private, so that users do not edit (and lost) the world data they receive from the server.
#...
def yourObjectGetter(self):
return self.__your_new_object #since your object is private, you will need a getter