|
这个问题是在我尝试利用pygraphviz嵌入我的C++代码绘制二叉树的时候发现的.找了半天资料,这里我把几种常用的C++调用
PYTHON利用 boost.python 的方法作一个总结,希望能让别人少走弯路,因为有些内容还找不到中文文档,虽然都不难但是开始摸索
还是费时间的.
我个人认为boost.python真的是非常的COOL,基本上不需要去学习那个看了就头大用着也不方便的python c api了,唯一的缺点
是目前相关的资料太少,甚至官网上也解释不够详细.
前面我写了一篇python嵌入c++的入门文章包括安装和环境配置,介绍了如何利用 boost.python方便的传递C++代码中的参数,调用 python函数.boost.python入门教程 ----python 嵌入c++
这个boost.python官网上的tourial也有介绍.
- 首先第一种常用方式是 python::boost::exec
#include
using namespace boost::python;
//引入python解释器
Py_Initialize();
//引入__main__ 作用域
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
exec("print('Hello world!')", main_namespace);
//exec + python command string + 作用域
- 第二种方法是利用boost::python::object对象
第一种方法虽然很好但是不方便和C++交互数据,如传递C++中的数据作为参数给python函数,以及C++接受python执行函数后
的返回值. 那么怎么用object调用python函数呢,很简单看下面的代码就了解了.
我在simple.py中定义了函数
def foo(int i = 3):
return i + 2008
这样一个简单的函数, 通过将simple.py利用boost::python::exec_file将其引入到__main__作用域,我们在__main__.__dict__
也就是main_namespace中取到命名为foo的函数对象,并将其转换成boost::python::object使用. 这里我们给这个object
同样命名为foo,调用foo(5)即调用python 函数foo(5)返回2013,注意在C++环境中要用extract将这个值取到.
object simple = exec_file("simple.py",main_namespace, main_namespace);
object foo = main_namespace["foo"];
int val = extract(foo(5));
cout G=AGraph()
>>> G.add_node('a')
>>> G.nodes()
['a']
>>> G.add_node(1) # will be converted to a string
>>> G.nodes()
['a', '1']
Attributes can be added to nodes on creation
>>> G.add_node(2,color='red')
该参数列表由一个普通参数和一个关键字参数构成,你可能会想上面的几种operator()的重载函数中没有这种形式啊?
没有关系,解决的办法是将普通参数在这里当作tuple看待,而且你只能这么做:)否则运行通不过的!
具体的办法是如果你的函数有n 个普通参数在关键字参数前面那么你就生成并传递一个有n个元素组成的tuple,
如果是形如foo(**kargs)这样的函数,那么你也需要先传递一个空tuple,
void sort(args_proxy const &args, kwds_proxy const &kwds);
x.sort(*tuple(), **dict(make_tuple(make_tuple("reverse", true))));
// 等价于 Python 调用 x.sort(reverse=true)
好了下面看一下我调用add_node的代码,注意add_node(1, color='red')表示生成一个node,它的关键字是1,而颜色是红色,
我也可能会调用 add _node(2, lable='abc')表示该节点关键字是2,而它将会被输出显示的标志是abc.
void print(std::string result = "huff_tree.dot") {
using namespace boost::python; //for tree printing
Py_Initialize();
object main_module = import("__main__");
object main_namespace = main_module.attr("__dict__");
exec("import pygraphviz as pgv", main_namespace);
exec("tree_graph = pgv.AGraph(directed=True,strict=True)", main_namespace);
object tree_graph = main_namespace["tree_graph"];
tree_graph.attr("add_node")(*make_tuple(1), **dict(make_tuple(make_tuple("label", "Jordan"))));
exec("tree_graph.graph_attr['epsilon']='0.001'", main_namespace);
exec("tree_graph.layout('dot')", main_namespace);
exec("tree_graph.write('huff_tree.dot')", main_namespace);
}
恩,看下生成的huff_tree.dot文件,node 的 key 是1, label是Jordan,完全正确:)
strict digraph {
graph [bb="0,0,70,36",
epsilon="0.001"
];
node [label="\N"];
1 [height="0.50",
label=Jordan,
pos="35,18",
width="0.97"];
}
图片显示如下:
关于上面代码dict(make_tuple(make_tuple()))的解释:
其实是这样的对这样一个tuple(tuple,tuple) 如 ((1,2),(3,4)) 执行dict操作得到 {1:2,3:4}
即dict(make_tuple(make_tuple(1,2),make_tuple(3,4))) = {1:2, 3:4}
而上面的例子women其实就是dict(make_tuple(make_tuple(1,2))这样里面只有一个tuple的特例。
|
|