Embeding Python & Extending Python with FFPython

简介: Introduction ffpython is a C++ lib, which is to simplify tasks that embed Python and extend Python. As the author, I am a developer for MMO server.

Introduction

ffpython is a C++ lib, which is to simplify tasks that embed Python and extend Python. As the author, I am a developer for MMO server. Mainly I use C++ to implement part that needs to response user's requests in realtime, while other logic part that needs to be modified frequently is implemented by Python. Python makes it possible to reload our part of the server when the server is running. Python is so easy that even my colleague with no programing skills can implement some npc script. When I was first in charge of integrating Python runtime interpreter to our C++ server, I used Boost.python. Somehow Boost.python helped me solve most problems about Python API especially parts of Python reference. But Boost.python is not perfect.

  • When exception happens while invoking python function by boost.python, boost.python doesn't provide interface to fetch traceback information.
  • Boost python is a big lib to some extent. Someone will find it much difficult who just wants to try to experience how embedding Python works.
  • Boost.pyhon supports badly to extend python by using C++ static function and class in runtime. Boost.python recommends to use dynamic library to extending python.
  • Someone who wants to learn example code using Python API will find it difficult to understand well boost.python codes, in my opinion.
  • If you have the need to convert data between C++ STL container and python object builtin, you have to implement these codes yourself, while Python reference is so annoying.

FFPython

Firstly, I implemented it just for converting data between C++ STL container and python object. Some of my colleagues have writes a lot of code using Python API directly. But there is some trap in some Python API even engineers who have a lot of experience using Python may have lost. PyDict_SetItem will auto increase reference key and value arguments, but other Python builtin structure API like PyTuple_SetItem will not increase reference the argument. It will cause memory leak. So I wanted to wrap operations about converting data between C++ STL container and Python builtin structure. Finally, I found some elegant ways to wrap embedding Python and extending Python by C++ template skills. So that is how FFPyhton was born.

Embedding Python

Sometimes I think it's easier to show codes to readers here. ^_^. But it will be forbidden by administrator if I post lots of code. O(n_n)O~. So see code files or Github.

When Embedding Python, such functions are most needed.

  • Fetch global variable of python script(or module). This happens when you use Python script as config files.
  • Call python function in script. That is the most useful interface. Two parts of it are important.
    1. It should be supported to use C++ builtin type and C++ STL container as argument.
    2. It should be supported to convert returned value of Python builtin types (like list, tuple, dict, string...) to C++ builtin types.
  • Fetch exception information when exception happens, especially traceback information. Because of feature of dynamic type, exception regularly happens even in online server, let alone debugging time. ffpython will throw std exception when Python exception happens. So it is much easier to print or log traceback info by outputexception.what() .
  • ffpython support nine arguments.
  • ffpython implemented by C++ template to wrap Python API. It is easy to understand how it works if you see the code.
 printf("sys.version=%s\n", 
ffpython.get_global_var<string>("sys", "version").c_str()); 

int a1 = 100; float a2 = 3.14f; string a3 = "OhWell";
ffpython.call<void>("fftest", "test_base", a1, a2, a3);
vector<int> a1;a1.push_back(100);a1.push_back(200);
list<string> a2; a2.push_back("Oh");a2.push_back("Nice");
vector<list<string> > a3;a3.push_back(a2);
ffpython.call<bool>("fftest", "test_stl", a1, a2, a3);
typedef map<string, list<vector<int> > > ret_t;
ret_t val = ffpython.call<ret_t>("fftest", "test_return_stl");

 

Extending Python

ffpython recommends to register C++ function/class in runtime. It works to design and develop MMO game server. So that is common use for me. There are some key points when embedding Python.

  • ffpython supports to register C++ static function. C++ builtin types and STL container can be as arguments.
  • C++ class can be registered to Python.

Register C++ static function, all base type supported. Arg num can be nine.

static int print_val(int a1, float a2, const string& a3, const vector<double>& a4)
{
    printf("%s[%d,%f,%s,%d]\n", __FUNCTION__, a1, a2, a3.c_str(), a4.size());
    return 0;
}

ffpython_t ffpython;//("ext1");
ffpython.reg(&print_val, "print_val");
ffpython.init("ext1"); 

 

Register C++ class, Python can use it just like builtin types.

class foo_t{

public:
    foo_t(int v_):m_value(v_){
    printf("%s\n", __FUNCTION__);
    }
    virtual ~foo_t(){
        printf("%s\n", __FUNCTION__);
    } 
    int get_value() const { return m_value; }
    void set_value(int v_) { m_value = v_; }
    void test_stl(map<string, list<int> >& v_) 
    {
        printf("%s\n", __FUNCTION__);
    }
    int m_value;
};
class dumy_t: public foo_t
{
public:
    dumy_t(int v_):foo_t(v_)
    {
        printf("%s\n", __FUNCTION__);
    }
    ~dumy_t()
    {
        printf("%s\n", __FUNCTION__);
    }
    void dump() 
    {
        printf("%s\n", __FUNCTION__);
    }
};
static foo_t* obj_test(dumy_t* p)
{
    printf("%s\n", __FUNCTION__);
    return p;
}
void test_register_base_class(ffpython_t& ffpython)
{
    ffpython.reg_class<foo_t, PYCTOR(int)>("foo_t")
            .reg(&foo_t::get_value, "get_value")
            .reg(&foo_t::set_value, "set_value")
            .reg(&foo_t::test_stl, "test_stl")
            .reg_property(&foo_t::m_value, "m_value");
};   

 

Summary

  • ffpython only one implements head file, it is easy to integrate to project.
  • ffpython is simply wrap for Python API, so it is efficient.
  • github: https://github.com/fanchy/ffpython
  • python2.5 python2.6 python2.7, win / linux
  • python3.x is being developed, but unfortunately, Python3.x API is so different to python2.x, even different between python3.2 and python3.3, Headache!!
目录
相关文章
|
9月前
|
传感器 安全 算法
【C语言】C语言可以做什么?
C语言因其高效、灵活和低级控制能力,被广泛应用于各个领域,从基础设施和科学计算到金融、交通和机器人技术。它在许多关键应用中展示了其不可替代的价值和广泛的适用性。
465 2
|
7月前
|
数据采集 监控 安全
电商数据接口实战:全量获取店铺商品的技术方案与进阶策略
该文档介绍了通过官方API获取店铺全量商品数据的技术实现与应用场景。主要涵盖四大方面:业务场景(如店铺运营监控、竞品分析等)、技术实现流程(包括环境准备、接口调用和分页策略)、数据结构解析与治理(如响应结构、数据处理建议),以及企业级解决方案设计(架构设计、性能优化、数据更新策略)。同时,强调了合规与安全实践,并提供了典型问题的解决方案。适用于电商中台项目,支持日均亿级商品数据处理。
|
机器学习/深度学习 自然语言处理 算法
【论文精读】TNNLS 2022 - 基于深度学习的事件抽取研究综述
事件抽取是从海量文本数据中快速获取事件信息的一项重要研究任务。随着深度学习的快速发展,基于深度学习技术的事件抽取已成为研究热点。文献中提出了许多方法、数据集和评估指标,这增加全面更新调研的需求。
849 0
|
传感器 自动驾驶 安全
无人驾驶汽车对人民的出行方式和生活方式产生了深远的影响
无人驾驶汽车对人民的出行方式和生活方式产生了深远的影响
无人驾驶汽车对人民的出行方式和生活方式产生了深远的影响
|
存储 分布式计算 Hadoop
ClickHouse(01)什么是ClickHouse,ClickHouse适用于什么场景
ClickHouse是一款高性能的列式存储OLAP数据库,由俄罗斯的Yandex公司开发,用于在线分析处理(OLAP)。它提供秒级大数据查询,适用于商业智能、广告流量等领域。ClickHouse速度快的原因包括列式存储、数据压缩、向量化执行和多线程分布式处理。然而,它不支持事务,不适合OLTP操作。相比Hadoop生态中的查询引擎,ClickHouse在大量数据查询上表现出色。一系列的文章详细介绍了ClickHouse的各个方面,包括安装、表引擎和使用场景。
2121 2
ClickHouse(01)什么是ClickHouse,ClickHouse适用于什么场景
|
安全 关系型数据库 数据库
上新|阿里云RDS PostgreSQL支持PG 16版本,AliPG提供丰富自研能力
AliPG在社区版16.0的基础上,在安全、成本、可运维性等多个方面做了提升,丰富的内核/插件特性支持,满足业务场景的需求
|
弹性计算 运维 监控
阿里云轻量应用服务器和ECS有什么区别?如何选择?十大区别对比
阿里云服务器分为轻量应用服务器和云服务器ECS,轻量是在云服务器ECS基础上推出的轻量级云服务器,轻量应用服务器是一款可快速搭建且易于管理的轻量级云服务器,提供基于单台服务器的应用部署、安全管理、可视化运维监控等服务,使用门槛低。轻量应用服务器结合WordPress等应用镜像,可以快速搭建所需Web环境
1530 0
阿里云轻量应用服务器和ECS有什么区别?如何选择?十大区别对比
|
存储 缓存 监控
ES写入过程和写入原理调优及如何保证数据的写一致性(下)
ES写入过程和写入原理调优及如何保证数据的写一致性(下)
|
存储 关系型数据库 MySQL
【MySQL】事务日志 undo log 详解
Redo log是事务持久性的保证,Undo log是事务原子性的保证。在事务中更新数据的前置操作其实就是要写入Undo log。事务需要保证原子性,也就是事务中的操作要么全部完成,要么什么也不做。但有时候事务执行到一半会出现一些情况,比如: 情况一:事务执行过程中可能遇到各种错误,比如服务器本身的错误,操作系统错误,甚至是突然断电导致的错误。 情况二:程序员可以在事务执行过程中手动输入ROLLBACK语句结束当前事务的执行以上情况出现,我们需要把数据改回原先的样子,这个过程称之为回滚,这样就可以造成一个假象:这个事务看起来什么都没做,所以符合原子性要求每当我们要对一条记录做改动。
|
存储 算法 Windows
3.9.4Cache写策略
计算机组成原理之Cache写策略
526 0