How to embed python into C ++ -- boost. Python: How to call functions that contain variable tuple and dict variables of keyword parameters in C ++

Source: Internet
Author: User

This problem occurs when I try to use pygraphviz to embed my c ++CodeI found it when I drew a binary tree. I found some materials for half a day. Here I will call several common C ++ calls

Python uses the boost. Python method to make a summary, hoping to reduce the detours of others, because some content still cannot find Chinese documents, although it is not difficult to start exploring

Time-consuming.

I personally think that boost. python is really a very cool. Basically, you don't need to learn about the python C API that is too easy to use after reading it. The only drawback is

At present, there are too few relevant materials, and even the official website does not provide detailed explanations.

I wrote an article about how to embed python into C ++.ArticleIncluding installation and environment configuration, this section describes how to use boost. Python to easily PASS Parameters in C ++ code, call Python function. Boost. Python getting started tutorial ---- embed python into C ++

Tourial on the boost. Python official website is also introduced.

 

    • The first common method is Python: boost: exec.
# Include <boost/python. HPP>
Using namespace boost: Python;
// Introduce Python Interpreter
Py_initialize ();
// Introduce _ main _ Scope
Object main_module =   Import ( " _ Main __ " );
Object main_namespace = Main_module.attr ( " _ Dict __ " );
  Exec ( "Print ('Hello world! ') " , Main_namespace );

// Exec + Python command string + Scope
    • The second method is to use the boost: Python: Object object

The first method is good,Inconvenient to interact with C ++ dataFor example, after passing data in C ++ as a parameter to a python function, and C ++ accepts python to execute a function

So how to use an object to call a python function? It's easy to see the following code.

I defined a function in simple. py.

Def Foo (INT I = 3 ):

Return I + 2008

Such a simple function. PY uses boost: Python: exec_file to introduce it to the _ main _ scope __. _ dict __

That is, the main_namespace obtains the function object named Foo and converts it to boost: Python: object. Here we will give this object

The same name is foo. Call Foo (5) to call the python function Foo (5) and return 2013. Note that extract <int> is used in the C ++ environment to get this value.

Object simple = Exec_file ( " Simple. py " , Main_namespace, main_namespace );
Object foo = Main_namespace [ " Foo " ];
Int Val = Extract < Int > ( Foo ( 5 ));
Cout <   " Python has caculated Foo "   < Val < Endl;
    • Different from C ++, Python Functions Support variable length parameters and keyword parameters. How can this problem be called?

If it is a simple Python function such as Foo (A, B, C), it can be called in the above form,Foo (* ARGs), Foo (** kargs), Foo (* ARGs, ** kargs)

Foo (n, ** kargs)How can I use boost: Python: object to call such functions in C ++?

 

Well, this is the focus of this Article. Let's take a look at what are the indefinite parameters and keyword parameters first. Let's copy the explanation from Rayong's blog, which is very clear.

Http://blog.csdn.net/lanphaday/archive/2009/05/08/4159346.aspx
Variable Parameter
In C/C ++, the variable parameters can be counted as the last improved course. Because its va_list, va_start, and va_end are intrusive, it is not easy to understand. In addition, because C/C ++ is a static strong-type language, data does not carry type information during running, therefore, an indefinite parameter function is more like a call Protocol, which requires communication between the function definer and the user through documents, annotations, and other methods; or like printf () the function uses the FMT parameter to implicitly specify the parameter type and then performs an explicit transformation.

Variable parameters are much simpler in Python. Looking back at the next year's C/C ++, in fact, va_list is a tuple implementation, because it can hold pointers of different data types (implemented through void ). Thanks to the boxing and unboxing operations in Python function calling, python can provide more concise implementation for access to indefinite parameters. For example:

Def Foo (* ARGs ):
For ARG in ARGs: Print ARG

In python, you can use * ARGs syntax to define variable parameters for functions. ARGs is equivalent to va_list of C/C ++. It is a tuple type parameter container, therefore, you can simply traverse all parameters without the so-called va_start and va_end.

In python,Variable parameters can be called directly using the tuple ParameterSuch:

Names = ('laiyonghao', 'denggao', 'liming ')

Foo (* names)#Attention symbol *

Keyword Parameter
Although the variable parameters bring a lot of convenience to the function, the keyword parameters in Python are especially fascinating. Keyword parameters are defined in the following format:

Def Foo (** kW): Pass

WhereKW is essentially a dict object., SoYou can call Foo like this.:

FOo (**{'A': 1, 'B': 2, 'C': 3 })

Looks familiar? Right, in the "First Post" (http://blog.csdn.net/lanphaday/archive/2008/08/31/2857813.aspx) Dip example 2.1 has these lines of code:

If _ name _ = "_ main __":

Myparams = {"server": "mpilgrim ",

"Database": "master ",

"Uid": "sa ",

"PWD": "secret"

}

Print buildconnectionstring (myparams)

This buildconnectionstring (myparams) is similar to the Foo () call mentioned above, and it is more complicated to use the keyword parameter. In fact, this is not the case. If you use a keyword parameter, for example, 2.1, you can write it as concise:

Def buildconnectionstring (** Params ):

"Build a connection string from a dictionary of parameters.

Returns string ."""

Return ";". Join ("% s = % s" % (K, V) for K, V in Params. iteritems ())

 

If _ name _ = "_ main __":

Print buildconnectionstring (

Server = 'mpilgrim ',

Database = 'master'

Uid = 'sa'

Pwd = 'secret ')

In addition to being more elegant, it also improves the performance than the previous method.

This article from the csdn blog, reproduced please indicate the source: http://blog.csdn.net/lanphaday/archive/2009/05/08/4159346.aspx

OK. Next we will focus on how to call such functions with indefinite parameters and keyword parameters in C ++ in boost. Python?

Not introduced in torial, so let's look at the Manu of Boost: Python: object.

or directly view the Source Code

Template <Class U>
Class object_operators: Public def_visitor <u>
{
Public:
// Function call
//
Object operator () const;

Detail: args_proxy operator * () const;
 Object operator () (detail: args_proxy const & ARGs) const;
Object operator () (detail: args_proxy const & ARGs,
Detail: kwds_proxy const & kwds) const;
This is exactly what we need, () Operator overload, so as to support variable parameters, the first function in red above, and variable parameter + keyword parameter, the second function in red.

 

Class Template Object_operators Observer Functions
 
Object operator () const;
Template <class A0>
Object operator () (A0 const &) const;
Template <class A0, Class A1>
Object operator () (A0 const &, A1 const &) const;
...
Template <class A0, Class A1,... class an>
Object operator () (A0 const & A1, A1 const & A2,... an const & an) const;
Effects:Call <Object> (Object (* static_cast <u *> (this). PTR (), A1, A2,...)
This corresponds to a common Python function call.
 
Object operator () (detail: args_proxy const & ARGs) const;
Effects:Call object with arguments given by TupleARGs
Python function calls with variable parameters
 
Object operator () (detail: args_proxy const & ARGs,
Detail: kwds_proxy const & kwds) const;
Effects: Call object with arguments given by Tuple ARGs , And named arguments given by Dictionary Kwds
Call of Python functions corresponding to the variable parameter + keyword parameter dict

OK. Now we can use boost: Python: object to call all Python functions in C ++! Cool!

Let's look at a specific example:

In my attemptProgramWhen using pygraphviz, I need to call the following Python function.

 Add_node (self, N, ** ATTR) Method of pygraphviz. agraph. agraph instance
Add a single node n.

If n is not a string, conversion to a string will be attempted.
String Conversion will work if n has Valid String Representation
(Try STR (n) If you are unsure ).

>>> 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 ')

 

This parameter list consists of a common parameter and a keyword parameter. You may think that this form is not available in the overload functions of the above operator?

It doesn't matter. The solution isTreat common parameters as tuple hereAnd you can only do this :) otherwise, the Operation will fail!

The specific method is that if your function has n common parameters before the keyword parameter, you will generate and passA tuple consisting of n elements,

If it is a function like Foo (** kargs), you must first pass an empty tuple.,

 Void sort (args_proxy const & ARGs,Kwds_proxyConst & kwds );

X. Sort (* tuple (), ** dict (make_tuple ("reverse", true ))));
// It is equivalent to calling X. Sort (reverse = true) in Python)

Now let's take a look at the code for calling add_node. Note that add_node (1, color = 'red') indicates that a node is generated. The key word is 1, and the color is red,

I may also call Add _ node (2, lable = 'abc') to indicate that the keyword of this node is 2, and it will be displayed as ABC in the output.

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 ( " 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 );
}

 

Well, let's take a look at the generated huff_tree.dot file. The key of node is 1, and the label is Jordan, which is completely correct :)

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"];
}

The image is shown as follows:

 

Explanation of the above Code dict (make_tuple:

In fact, we can perform dict operations on such a tuple (tuple, tuple) such as (1, 2), (3, 4) to get}

Dict (make_tuple (), make_tuple () =}

In the preceding example, women is actually a special tuple case in dict (make_tuple.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.