1. 程式人生 > >Boost Python學習筆記(四)

Boost Python學習筆記(四)

xtra public string 轉換 TP 簡單實現 amp dir rst

你將學到什麽

  • 在Python中調用C++代碼時的傳參問題

基礎類型

Python的字符串是常量,所以C++函數參數中的std::string &必須為const

修改源文件(main.cpp)

#include <iostream>
#include <boost/python.hpp>
#include "boost_wrapper.h"

using namespace boost::python;
using namespace boost::python::detail;

int main()
{
  Py_Initialize();
  if (!Py_IsInitialized())
  {
    std::cout << "Initialize failed" << std::endl;
    return -1;
  }

  try
  {
    object sys_module = import("sys");
    str module_directory(".");
    sys_module.attr("path").attr("insert")(1, module_directory);
    object module = import("zoo");
    module.attr("show")();
  }
  catch (const error_already_set&)
  {
    PyErr_Print();
  }
  Py_Finalize();
  return 0;
}

Python腳本如下(build/zoo.py)

import boost

def show():
    boost.add(2, 4)
    boost.xstr("fwd")

if __name__ == ‘__main__‘:
    pass

導出頭文件如下(include/boost_wrapper.h)

#pragma once

#include <string>

void add(int x, int y);
void xstr(std::string const &x);

導出實現如下(src/boost_wrapper.cpp)

#include <iostream>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include "boost_wrapper.h"

using namespace boost::python;
using namespace boost::python::detail;

void add(int x, int y)
{
  std::cout << "add: " <<  x + y << std::endl;
}

void xstr(std::string const &x)
{
  std::cout << "string: " << x << std::endl;
}

BOOST_PYTHON_MODULE_INIT(boost)
{
  def("add", add);
  def("xstr", xstr);
}

標準庫

修改源文件(main.cpp)

#include <iostream>
#include <boost/python.hpp>
#include "boost_wrapper.h"

using namespace boost::python;
using namespace boost::python::detail;

int main()
{
  Py_Initialize();
  if (!Py_IsInitialized())
  {
    std::cout << "Initialize failed" << std::endl;
    return -1;
  }

  try
  {
    object sys_module = import("sys");
    str module_directory(".");
    sys_module.attr("path").attr("insert")(1, module_directory);
    object module = import("zoo");
    module.attr("show")();
  }
  catch (const error_already_set&)
  {
    PyErr_Print();
  }
  Py_Finalize();
  return 0;
}

方式一

這種方式主要使用vector_indexing_suite定義一個新的Vector類型XVec

Python腳本如下(build/zoo.py)

import boost

def show():
    l = boost.XVec()
    l.append(2)
    l.append(3)
    l.append(4)
    boost.show_list(l)
    for i in l:
        print(i)

if __name__ == ‘__main__‘:
    pass

導出頭文件如下(include/boost_wrapper.h)

#pragma once

#include <vector>

void show_list(std::vector<int> &v);

導出實現如下(src/boost_wrapper.cpp)

#include <iostream>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
#include "boost_wrapper.h"

using namespace boost::python;
using namespace boost::python::detail;

void show_list(std::vector<int> &v)
{
  for (auto item : v)
  {
    std::cout << item << " ";
  }
  std::cout << std::endl;
  v.push_back(7);
}

BOOST_PYTHON_MODULE_INIT(boost)
{
  class_<std::vector<int> >("XVec").def(vector_indexing_suite<std::vector<int> >());
  def("show_list", show_list);
}

方式二

這種方式主要是通過boost :: python :: converter :: registry :: push_back函數來註冊自定義轉換函數,主要實現兩個函數convertible(用於檢測Python側傳入的對象是否符合轉換條件,比如是不是叠代器、裏面的元素類型是不是對的等,這邊只是簡單實現下)和construct(提取Python側傳入的對象元素,然後構造C++側的對象,這邊也只是簡單實現了下),高級實現方式可以參考cctbx_project的scitbx/array_family/boost_python/regress_test_ext.cppscitbx/boost_python/container_conversions.h文件,不過參數必須是右值(註意函數參數的const修飾符不能刪)

Python腳本如下(build/zoo.py)

import boost

def show():
    boost.show_list([2,3,4])

if __name__ == ‘__main__‘:
    pass

導出頭文件如下(include/boost_wrapper.h)

#pragma once

#include <vector>

void show_list(std::vector<int> const &v);

導出實現如下(src/boost_wrapper.cpp)

#include <iostream>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/extract.hpp>
#include <boost/python/to_python_converter.hpp>
#include "boost_wrapper.h"

using namespace boost::python;
using namespace boost::python::detail;

void show_list(std::vector<int> const &v)
{
  for (auto item : v)
  {
    std::cout << item << " ";
  }
  std::cout << std::endl;
}

template<class ContainerType>
class from_python_list
{
public:
  from_python_list()
  {
    boost::python::converter::registry::push_back(&convertible, &construct, boost::python::type_id<ContainerType>());
  }

  static void* convertible(PyObject *obj_ptr)
  {
    if (!(PyList_Check(obj_ptr)
         || PyTuple_Check(obj_ptr)
         || PyIter_Check(obj_ptr)
         || PyRange_Check(obj_ptr)
         || (PyObject_HasAttrString(obj_ptr, "__len__") && PyObject_HasAttrString(obj_ptr, "__getitem__"))))
      return 0;

    return obj_ptr;
  }

  static void construct(PyObject *obj_ptr, boost::python::converter::rvalue_from_python_stage1_data* data)
  {
    boost::python::handle<> obj_iter(PyObject_GetIter(obj_ptr));
    void *storage = ((boost::python::converter::rvalue_from_python_storage<ContainerType>*)data)->storage.bytes;
    new (storage) ContainerType();
    data->convertible = storage;
    ContainerType &result = *((ContainerType*)storage);

    while (true)
    {
      boost::python::handle<> py_hdl(boost::python::allow_null(PyIter_Next(obj_iter.get())));
      if (PyErr_Occurred())
        boost::python::throw_error_already_set();
      if (!py_hdl.get())
        break;
      boost::python::object py_obj(py_hdl);
      boost::python::extract<typename ContainerType::value_type> obj(py_obj);
      result.push_back(obj);
    }
  }
};

BOOST_PYTHON_MODULE_INIT(boost)
{
  def("show_list", show_list);
  from_python_list<std::vector<int>>();
}

Boost Python學習筆記(四)