30 Ocak 2018 Salı

C++'tan Python Kullanmak

Giriş
Şu satırı dahil ederiz.
#include <boost/python.hpp>
Şu satırı dahil ederiz.
using namespace boost::python;
Ya da şu satırı dahil ederiz.
namespace bp = boost::python;
Python Türevleri
Açıklaması şöyle
For example, every single currently existing Python implementation uses a compiler:

CPython has an ahead-of-time compiler that compiles Python source code to CPython byte code.

PyPy has an ahead-of-time compiler that compiles Python source code to PyPy byte code, then it has another compiler that compiles PyPy byte code to native machine code (or ECMAScript when running in a browser).

IronPython has an ahead-of-time compiler that compiles Python source code to DLR Trees, then it has another compiler that compiles DLT Trees to .NET CIL byte code, which the .NET runtime then may or may not compile to native machine code.

GraalPython has an ahead-of-time compiler that compiles Python source code to Truffle ASTs, then Truffle takes over and compiles Truffle ASTs to JVM byte code or native machine code, in the first case, the JVM may then in turn compile the JVM byte code to native machine code.
main metodu
Örnek
Şöyle yaparız.
int main()
{
  Py_Initialize();//Initialize the python interpreter  
  try {
   ...
  } catch (bp::error_already_set const &) {
    PyErr_Print();
  }
  return 0;
}
Örnek
Şöyle yaparız.
int main()
{
  using namespace boost::python;

  Py_Initialize(); //Initialize the python interpreter
  object main_module = import("__main__");
  object main_namespace = main_module.attr("__dict__");
  ...
}
Örnek
Bu sefer C++ kodunu python metoduna parametre olarak geçiyoruz. Elimizde C++ sınıfı olsun.
class PyData
{
public:

  PyData() {}

  float m_slope;
  float m_compliance;

  boost::python::tuple    m_TORSO_LV;
  boost::python::list     m_DsOsAVS;
  boost::python::list     m_RF_FORCES;
  boost::python::list     m_LF_FORCES;

  void InitData()
  {
    // simulate setting up data
    m_slope = 1.0;
    m_compliance = 2.0;

    m_TORSO_LV = boost::python::make_tuple(3.0, 4.0, 5.0);

    m_DsOsAVS.append(boost::python::make_tuple(10.0, 11.0, 12.0));
    m_DsOsAVS.append(boost::python::make_tuple(20.0, 21.0, 22.0));

    // etc.
  }

  ~PyData() {}
};
 python'a tanıtmak için şöyle yaparız.
BOOST_PYTHON_MODULE(pydata) {
boost::python::class_<PyData>("PyData")
    .def_readwrite("Torso_LV", &PyData::m_TORSO_LV)
    .def_readwrite("DsOsAVs", &PyData::m_DsOsAVS)
    .def_readwrite("RF_FORCES", &PyData::m_RF_FORCES)
    .def_readwrite("LF_FORCES", &PyData::m_LF_FORCES)
    .def_readwrite("slope", &PyData::m_slope)
    .def_readwrite("compliance", &PyData::m_compliance)
    ;
};
python script'i şöyle olsun.
def predict_on_data(o):
    print "In Python:"
    print repr(o)
    # print the data members in o
    print "o.slope is " + repr(o.slope)
    print "o.compliance is " + repr(o.compliance)
    print "o.Torso_LV is " + repr(o.Torso_LV)
    print "o.m_DsOsAVs is " + repr(o.DsOsAVs)
    # modify some data
    o.slope = -1.0
    o.compliance = -2.0
python'u ilklendirmek için şöyle yaparız. initpydata modül macrosu ile gelir.exec_file ile python yüklenir. global [..] çağrısı ile metod bulunur. Bu metoda PyData sınıfı parametre olarak geçilir.
int main (int argc, char * argv[])
{
  Py_Initialize();

  initpydata();

  boost::python::object main=boost::python::import("__main__");
  boost::python::object global(main.attr("__dict__"));
  boost::python::object result =
    boost::python::exec_file("/home/andy/Python2.py", global, global);
  boost::python::object predict_on_data = global["predict_on_data"];
  if (!predict_on_data.is_none())
  {
    boost::shared_ptr<PyData> o(new PyData);
    o->InitData();
    predict_on_data(boost::python::ptr(o.get()));
    std::cout << "values in c++ object are now: " <<
     o->m_slope << " and " << o->m_compliance << std::endl;
  }

  return 0;
}

PyImport_AppendInittab
C++'tan python kullanırken önce python'a bir modül eklemek istersek şöyle yaparız.
struct Foo
{
    void f() {}
};

BOOST_PYTHON_MODULE(FooModule)
{
  bp::class_<Foo>("Foo")
    .def("f", &Foo::f)
    ;
}

int main() {
  try
  {
    PyImport_AppendInittab("FooModule", &initFooModule);
    Py_Initialize();
    ...
    return 0;
  }
  catch(const bp::error_already_set&)
  {
    std::cerr << ">>> Error! Uncaught exception:\n";
    PyErr_Print();
    return 1;
  }
}
object Sınıfı
python object Sınıfı yazısına taşıdım.

Free Style Metodlar
call metodu
Python metodunu callback olarak çağırmak istersek şöyle yaparız.
#this is the variable that will hold a reference to the python function
PyObject *py_callback;

#invoke the python function
bp::call<void>(py_callback);
exec metodu
exec metodu yazısına taşıdım.

exec_file metodu
Örnek 
Şöyle yaparız.
std::string a_file = "py-test-dog.py";
python::object main_module  = python::import("__main__");
python::object global(main_module.attr("__dict__"));
try
{
  python::object ignored      = python::exec_file(
            a_file.c_str() , global, global );
  std::cout << "Executed script" << std::endl;
}
catch(std::exception& e)
{
  std::cout << e.what() << std::endl;
}
Örnek 2
Elimizde python olsun.
class MyPythonClass:
    def Func1(self, param):
        return
    def Func2(self, strParam):
        return strParam
Bu sınıfı yükleyip Func2 metodunu çalıştırmak için şöyle yaparız.
namespace python = boost::python;
python::object main = python::import("main");
python::object mainNamespace = main.attr("__dict__");

//add the contents of the script to the global namespace
python::object script = python::exec_file(path_to_my_script, mainNamespace);

//add an instance of the object to the global namespace
python::exec("foo = MyPythonClass()", mainNamespace);
//create boost::python::object that refers to the created object
python::object foo = main.attr("foo");

//call Func2 on the python::object via attr
//then extract the result into a const char* and assign it to a std::string
//the last bit could be done on multiple lines with more intermediate variables
// if desired
const std::string func2return = python::extract<const char*>(foo.attr("Func2")
  ("hola"));
assert(func2return == "hola");
handle_exception metodu
Şöyle yaparız.
if (bp::handle_exception(...) )
{
  if (PyErr_Occurred())
  {
    std::cout << "Python Error detected"
              << std::endl;
    PyErr_Print();
  }
  else
  {
    std::cout << "A C++ exception was thrown  for which "
              << "there was no exception translator registered."
              << std::endl;
    }
}
import metodu
Bu metodu çağırmadan önce Python yüklenmiş olmalıdır. Şöyle yaparız.
// Add the current working directory to the python path variable
// so that chart.py can be imported.
setenv("PYTHONPATH", ".", 1);
Py_Initialize();
Örnek 1
İsmi belirtilen python betiğini C++ koduna dahil eder. Elimizde test_module.py isimli dosya olsun. Şöyle yaparız.
bp::object a = bp::import ("test_module");
how to load a python module için kolaylık sağlayan bir metod var. Kolay import için şöyle yaparız.
namespace bp = boost::python;

bp::object import(const std::string& module, const std::string& path,
  bp::object& globals)
{
  bp::dict locals;
  locals["module_name"] = module;
  locals["path"]        = path;

  bp::exec("import imp\n"
           "new_module = imp.load_module(module_name, open(path), path, 
           ('py', 'U', imp.PY_SOURCE))\n",
           globals,
           locals);

  return locals["new_module"];
}
Örnek 2
Şöyle yaparız.
bp::object main    = bp::import("__main__");
bp::object globals = main.attr("__dict__");
bp::object module  = import("test", "test.py", globals);
bp::object run     = module.attr("run");
Örnek 3
python modülü yüklendikten sonra C++ metodu gibi kullanamayız. Şu kod derlenmez.
// Import the chart module
bp::object mod = py::import("chart");
// Create the chart object
bp::object myChart = mod.attr("Chart")();
// Show the chart
myChart.show();
Hata olarak şunu alırız.
error: class boost::python::api::object has no member named show
    myChart.show();
Şöyle yapmak gerekir.
bp::object run  = module.attr("show");
make_function metodu
Şöyle yaparız. callback python'a verilebilir. Böylece python çalışırken bizi tetikler.
void callback_handler(bp::object ch
    , bp::object method
    , bp::object properties
    , std::string const& body)
{
    std::cout << "in handler: " << body << std::endl;
}

bp::object h = bp::make_function(callback_handler);
make_tuple metodu
Elimizde şöyle bir nesne olsun.
PyObject * ret;
Şöyle yaparız.
boost::python::tuple t = boost::python::make_tuple(true, boost::python::handle<>(ret));





Hiç yorum yok:

Yorum Gönder