这几天开始研究Boost python,因为项目需要,要采用pyhton作为游戏服务器的脚本处理语言。由于之前没有接触过python,所以学习起来非常费劲,其实学什么都一样,万事开头难嘛。
在学习Boost Python之前呢,我想先了解了解Python,到底是什么东西。大家可以看看介绍http://baike.baidu.com/view/21087.htm。
在网上下了一个pyhton2.4的软件,安装后,开始了我的python学习。
先写个hello world吧。
很简单 print "hello world",就是这么简单,python是一门解释型语言,无需编译,非常的方便。
接着,就是复杂的和Boost相关的东西了,整得我非常头疼,而且网上相关资料非常的少,让我很是郁闷。
首先,下载1.36版本的Boost,进入控制台,进入到boost根目录,然后运行
bjam "-sVC80_ROOT=D:\Program Files\Microsoft Visual Studio 8\VC" "-sTOOLS=vc-8_0" --with-python stage (只编译python库),编译boost::python库,如果不出错的话,在bin.v2下面将生成一个python的文件夹,编译完成后,这里将可以找到Boost::python相关的库文件和dll。编译完之后,将这些dll和lib文件拷贝到C\PlatformSDK\Lib下面,以后就不用再设置库目录了。
完成之后,我进入到boost python的目录,里面有一个example,我用bjam运行之后,发现怎么也不好用,怎么也编译不出。Pyd文件出来,费了好几天,网上也没有相关的资料。
后来,我放弃了这种用bjam的编译方法,决定自己写一个c++工程来编译,我参考了
http://www.builder.com.cn/2008/0530/893201.shtml这篇文章,建立了一个dlld工程,来对python做扩展。写了一个很简单的hello world
char const* greet()
{
return "hello python";
}
int get()
{
int a = 10;
a++;
return a;
}
BOOST_PYTHON_MODULE(PythonDll)
{
boost::python::def("greet",greet);
boost::python::def("get",get);
}
编译成功后,生成了一个PythonDll.dll文件,注意,工程文件必须要和你导出的模块文件同名。
然后,将PythonDll.dll改名为Python.pyd文件,这是一个不模块文件后缀名,必须这样才能被python载入,很变态。
建立一个 test.py文件,
Import PythonDll
Print PythonDll.greet()
Print PythonDll.get()
你将会看到输出:
hello python
11
这就是简单的Boost python运用,这里是用c++为python写扩展。
接下来,我们再来看看更为复杂的扩展形式,我相信,大家用c++,用的最多的应该就是对象了,如果对象不能导出来,用python就毫无意义了,多说无益,我们继续。
Python是完全面向对象的,在python中,任何东西都是一个对象.大家可以看看<<python 核心编程>>
我们先来写一个c++类吧.我们生成一个PythonDll项目,设置成动态链接库。
加入以下代码
Class Player
{
public:
Player(int height,int age):
_height(height),_age(age){}
void SetHeight(int hei)
{
_height = hei;
}
int GetHeight() const
{
return _height;
}
void SetAge(int age)
{
_age = age;
}
int GetAge() const
{
return _age;
}
private:
int _height;
int _age;
};
这是一个c++类,有构造函数,方法,属性,我们将要在python中使用它。
现在我们将c++对象用Boost::python导出来.
BOOST_PYTHON_MODULE(PythonDll)
{
class_<Player>("Player",init<int,int>()) //导出构造函数和参数init<int,int>为参数列表
.def("SetHeight",&Player::SetHeight)
.def("GetHeight",&Player::GetHeight)
.def("SetAge",&Player::SetAge)
.def("GetAge",&Player::GetAge)
.def_readonly("Height",&Player::_height)
.def_readonly("Age",&Player::_age)
;
}
导出的模块名字必须和工程名字一样,大家可以在配置选项中将导出的文件改成Python.pyd。因为Python只能import pyd文件,不知道为什么。。。
然后我们编译工程,将会生成一个Python.pyd文件。
接着我们创建一个python脚本文件,写入以下代码
import PythonDll;
player = PythonDll.Pla(178,24);
print "Yout age =%d"%player.GetAge();
print "Yout height =%d"%player.GetHeight();
print "i will set your age and height";
player.SetHeight(170);
player.SetAge(15);
print "Yout age =%d"%player.GetAge();
print "Yout height =%d"%player.GetHeight();
输出结果为:
Yout age =24
Yout height =178
i will set your age and height
Yout age =15
Yout height =170
之前讲的是用c++做python的扩展,用的都是用c++封装成一个dll,我以为python只能调用c++写的dll扩展,今天在exe工程中写了一个扩展,导出pyd后,用python一测,发现原来也是可以的,兴奋一下下。
那么接下来就会轻松些了,我最近一直在研究,如何让python和c++非常自由的(就像lua)调用呢?
C++ 内嵌Pyhton
下面的例子是从boost文档中来的:
#include <iostream>
#include <string>
#include <boost/python.hpp>
#include <boost/ref.hpp>
#include <vector>
using namespace boost::python;
void greet()
{
object main = import("__main__");
object global(main.attr("__dict__"));
// Define greet function in Python.
object result = exec(
"def greet(a): \n"
" return 'Hello %s from Python!' % a \n",
global, global);
object greet = global["greet"];
list lst;
lst.append(1);
lst.append(2);
object r = greet(lst);
std::string message = extract<std::string>(r);
std::cout << message << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
Py_Initialize();
greet();
system("Pause");
return 0;
}
以上的代码是C++内嵌python的简单代码,该代码内嵌了一小段python代码,然后调用并且执行。
当然我们还可以将整个python文件装载进来,里面的文件可以任意的调用,看一个例子。
C++:
Py_Initialize();
// Retrieve the main module.
main = import("__main__");
// Retrieve the main module's namespace
global = main.attr("__dict__");
// Define greet function in Python.
result = exec_file("test.py",
global, global);
//调用python中的变量
std::cout<<"number="<< extract<int>(global["number"])<<endl;
//调用python的test方法,并传入参数给python
int a = extract<int>(global["test"](10));
Test.py文件
import kengine_test;
number = 65;
def test(a):
print a;
return a;
输出结果为:65 10
C++与python自由交互(内嵌和扩展)
做为脚本语言,能够实现自由交互(内嵌和扩展)是非常不错的事情,上面讲的两节,分别介绍了c++扩展python和c++内嵌python,那么接下来,我们将介绍如果实现c++和python的自由交互。也就是集内嵌和扩展并用,这在游戏开发是比较重要的。
看个例子
C++文件。
class Player
{
public:
Player(int height,int age): _height(height),_age(age){}
void SetHeight(int hei) { _height = hei;}
int GetHeight() const { return _height;}
void SetAge(int age){ _age = age;}
int GetAge() const { return _age;}
public: int _height;
int _age;
};
vector<Player*> g_PlayerList;
void AddPlayer(int height,int age)
{
Player* pl = new Player(height,age);
g_PlayerList.push_back(pl);
}
void ClearPlayer()
{
vector<Player*>::iterator itr = g_PlayerList.begin();
while (itr != g_PlayerList.end())
{
delete *itr;
itr++;
}
g_PlayerList.clear();
}
BOOST_PYTHON_MODULE(kengine_test)
{
def("AddPlayer",AddPlayer);
def("GetPlayerCount",GetPlayerCount);
def("ClearPlayer",ClearPlayer);
}
Int main()
{
try
{
Py_Initialize();
main = import("__main__");
global = main.attr("__dict__");
result = exec_file("test.py",
global, global);
}catch(std::exception& e)
{
std::cout<<e.what()<<endl;
}
//调用python中定义的CreatePlayer()
Bool res = extract<bool>(global["CreatePlayer"](10,20));
Std::out<<"玩家个数"<<GetPlayerCount()<<endl;
Return 0;
}
Python文件
Import kengine_test;
def Createplayer(height,age):
Kengine_test.AddPlayer(height,age);
Return true;
输出结果:玩家个数1