The previous project was C + + embedded python, which was easy to develop, and the logic business could be put into Python for development, easily modified, and extended functionality. But I do not have a detailed study of C + + embedded Python details, this time in detail. First we simply call a Python py script using C + + and then use the objects and methods in C + + through Python. The python we use is 2.7.11
1. Using Python features in C + +, for example, we write a show.py with the following code:
def Show (name): return " " + Name
This Python script is simply too simple to have any explanation. Then simply write a C + + function to simply call the function in this show.py show:
#include <Python.h>#include<iostream>using namespacestd;voidpython_test () {Py_setpythonhome ("d:/python27"); Py_initialize (); Pyobject* Pmodule = Pyimport_importmodule ("Show"); if(!pmodule) {cout<<"Import Python module test failed."<<Endl; return; } pyobject* PFunc = pyobject_getattrstring (Pmodule,"Show"); if(!PFunc) {cout<<"Import python func failed."<<Endl; return; } pyobject* Pparam = Py_buildvalue ("(s)","hahaha"); Pyobject* PResult =Pyobject_callobject (PFunc, Pparam); if(pResult) {Char* PBuf =NULL; intNbufsize =0; //if (Pyarg_parsetuple (PResult, "Si", &pbuf, &nbufsize))//{ //cout << "buf=" << pBuf << Endl; //cout << "buf size=" << nbufsize << Endl; //} if(Pyarg_parse (PResult,"s", &PBuf)) {cout<<"buf="<< PBuf <<Endl; }} py_decref (Pparam); Py_decref (PResult); Py_finalize (); return;}intMain () {python_test ();}
Here are a few places to note:
(1) First py_setpythonhome ("d:/python27"); This statement is used to set the Python script directory, if not set this directory, we do not know which directory Python went to read our script
(2) Py_buildvalue ("(s)", "hahaha"); Even if you only need a parameter here, you also need to use a tuple to pass the parameter, otherwise the Python parsing module will be error, it does the parameter type judgment inside.
(3) If the show function returns a normal parameter, we use Pyarg_parse to parse it, and if it is a tuple, we use Pyarg_parsetuple to parse it. Can not be mixed, or internal error.
It's very simple from the code, but it's not as simple as starting the deployment environment, because the python we installed by default is no Python27_d.lib and Python27_d.dll 2 files, specifically how to solve the python environment problem, see section Two.
2. Python code compilation
Previously said that the default installation of Python is not python27_d.lib and python27_d.dll these 2 files, I try to download these 2 files separately from the Internet, but the minor version number mismatch will also appear runtime crash. So I chose to download the python2.7.11 source code from the Internet, and then compile it myself. However, this compilation is generally very simple, I am using vs2012 compiled under Windows, the main points to note:
(1) using Pcbuild in the Pcbuild.sln, directly open, and then the VS in the selected Python project, directly compiled, my compilation process is no error, some warnings, we directly ignore. In debug mode, Python27_d.lib and Python27_d.dll are generated directly, and Python27_d.exe
(2) Although we have python27_d.lib and Python27_d.dll, and then in the previous test project to add a good include and Lib directory, compile, will be prompted to find the Pyconfig.h this file. This is because this file is unique under Windows, we need to copy this file in the PC directory to the Include directory, and then compile, it can be done normally.
3. Python calls C + + objects
Python calls the C + + interface in a variety of ways. Usually Python calls the C + + interface is a feature extension, the C + + functionality is compiled into a dynamic library, and then python through ctypes to import library files, under Windows is dll,linux under the so file, this use is relatively simple, and the example is very much, no longer introduced. In many complex projects, such as games, where we want to manipulate the player object in Python, it is cumbersome and inconvenient to manipulate the Player object instance if the module is directed into a library file. We use a dynamic approach to:
In the example we create a new 2 C + + class, a person, a personwrap. The person object represents someone, Personwrap is a Python interface extension for people, and the Person.h code is as follows:
#ifndef Person_h#definePerson_h#include<string>using namespacestd;classPerson { Public: Person () {}~Person () {}voidSetName (Const string&_name) {Name=_name; } string&GetName () {returnname; }Private: stringname;};#endif
The PersonWrap.h code is as follows:
#ifndef Person_wrap_h#definePerson_wrap_h#include<Python.h>#include"Person.h"classPersonwrap { Public: Staticpyobject* SetName (pyobject* self, pyobject*args) {cout<<"Wrap SetName"<<Endl; intPERSONADDR =0; Char* PName =NULL; if(! Pyarg_parsetuple (args," is", &personaddr, &pName)) { returnNULL; } Person* p = (person*) personaddr; P-SetName (pName); returnPy_buildvalue ("I",0); } Staticpyobject* GetName (pyobject* self, pyobject*args) { intPERSONADDR =0; if(! Pyarg_parsetuple (args,"I", &personaddr)) { returnNULL; } Person* p = (person*) personaddr; string& name = P->GetName (); returnPy_buildvalue ("s", Name.c_str ()); } Staticpyobject* GetDesc (pyobject* self, pyobject*args) { returnPy_buildvalue ("s","whoknows"); } Staticpyobject* Createperson (pyobject* self, pyobject*args) {cout<<"Wrap Create person"<<Endl; Char* PName =NULL; if(! Pyarg_parsetuple (args,"s", &pName)) { returnNULL; } Person* p =NewPerson (); P-SetName (pName); returnPy_buildvalue ("I", p); }}; Pymethoddef wrapmethods[]= { {"SetName", Personwrap::setname, Meth_varargs,"SetName"}, {"GetName", Personwrap::getname, Meth_varargs,"GetName"}, {"GetDesc", Personwrap::getdesc, Meth_varargs,"GetDesc"}, {"Createperson", Personwrap::createperson, Meth_varargs,"Createperson"}, {null, NULL,0, NULL}}; Pymodinit_func Initpythonwrap () {Pyobject*module; Module= Py_initmodule ("Pythonwrap", wrapmethods);}#endif
The code for the person class is very simple and does not need to be explained. Personwrap for the interface of person, you can see that the personwrap is a static function, this is to be able to export the interface for Python to use, while defining a wrapmethods array, These interfaces are exported in the manner defined by the Python method. Finally, a Initpythonwrap method is used to initialize the module dynamically. This allows our Ptyhon script to be called.
However, you need to add initpythonwrap () to the main function, otherwise it will not take effect. The Python code we tested is as follows:
import sys import Pythonwrap def Show (name): Person = Pythonwrap.createperson ( tom " jim ) hello " + pythonwrap.getname (person)
As you can see from the Python script, we import our dynamically generated Pythonwrap module and then call its interface as casually as any other ordinary Python module. It should be noted that our person object is a C + + object, according to the document query, if it is not conducive to third-party plug-ins can not directly pass C + + objects to Python, so we at the time of outgoing and incoming, is the person object pointer is passed through the whole way, Then force a pointer conversion.
If in debug mode, when we call Python's show function, when we use the interface in the Pythonwrap, we will enter our C + + code, debugging is more convenient. But there are still some problems, if our SetName interface is written like this:
Staticpyobject* SetName (pyobject* self, pyobject*args) {cout<<"Wrap SetName"<<Endl; intPERSONADDR =0; Char* PName =NULL; if(! Pyarg_parsetuple (args," is", &personaddr, &pName)) { returnNULL; } Person* p = (person*) personaddr; P-SetName (pName); returnNull; }
Then this interface can only be called once, the second call will not be triggered, should be for the return value, Python module code to do a special processing, and now do not know the specific reason. I'll add it after we figure it out later.
C + + embedded python, and the two mix