使用c/c++扩展Python

本文详细介绍了如何使用C/C++扩展Python,以提升游戏开发中密集计算的性能,包括创建内建对象、调用库函数和系统调用,通过CMakeLists.txt配置及编写Python扩展模块的方法,供开发者参考和实践。
摘要由CSDN通过智能技术生成

使用c/c++扩展Python

使用python做开发的时候,如果有些业务对性能有要求,可以考虑使用c/c++来实现Python的模块,例如游戏开发中,可以使用Python完成一些玩法逻辑,但是技能结算等这些高密度计算部分如果放在python实现,那么性能不是很理想,这个时候可以把这部分弄到c/c++中来实现。

使用c/c++来写扩展模块,可以实现Python无法直接完成的功能,比如:

1、实现一个新的内建对象类型;

2、调用c/c++库函数和系统调用。

实现方案

CMakeLists.txt编写

因为我们开发的是Python的扩展,所以必需include Python的头文件 <Python.h>。

在CMakeLists.txt中,可以使用 find_package 来自动寻找python的头文件路径。

cmake_minimum_required(VERSION 3.10)
project(demo)
set(CMAKE_CXX_STANDARD 11)
find_package(PythonLibs 2.7 REQUIRED)
message(STATUS "Python Include = ${PYTHON_INCLUDE_DIRS}")
include_directories(${PYTHON_INCLUDE_DIRS})
add_library(${PROJECT_NAME} SHARED library.cpp)
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "")

c++代码编写

我们接下来开发一个最简单的add函数。

首先,需要在代码中包含Python头文件

#include <Python.h>

Python头文件中包含了Python的C API,注意:由于Python可能会定义一些预处理,并影响某些系统的标准头文件,因为必需将 #include <Python.h> 放在最前面。

接着来实现我们的add函数

static PyObject* add(PyObject* self, PyObject* args){
    int a, b;
    if (!PyArg_ParseTuple(args, "ii", &a, &b)){
        return nullptr;
    }
    int sum = a + b;
    PyObject* ret = PyLong_FromLong(sum);
    return ret;
}

函数add的参数和返回值都是 PyObject类型,参数 args 表示从Python中传进来的参数列表,可以用 PyArg_ParseTuple 转换为 C/C++的数据类型,最后再用 PyLong_FromLong 将计算结果转为PyObject类型返回。

方法列表定义了我们这个模块中可以给外部调用的接口,比如:

static PyMethodDef MyDemoMethods[] = {
        {"addx", add, METH_VARARGS, "add two integers"},
        {nullptr, nullptr, 0, nullptr},
};

定义了一个 addx, 之后使用这个模块的时候就可以用 demo.addx(123, 456) 来进行调用了。

每一个方法定义由四个元素组成 {函数名称,函数实体,flag,函数描述},其中flag一般是:METH_VARARGS 或者 METH_VARARGS|METH_KEYWORDS。

  • METH_VARARGS: 表示函数期望python传进来的参数是一个可以被 PyArg_ParseTuple解析的元组;

  • METH_KEYWORDS: 设置这个标志位表示传经来的参数支持keyword,这时候函数实现需要支持第三个参数 PyObject *,并用PyArg_ParseTupleAndKeywords 来解析参数,比如:

    static PyObject *hello3(PyObject *self, PyObject *args, PyObject *kwdict){
        int voltage;
        char *state = "a stiff";
        char *action = "voom";
        char *type = "Norwegian Blue";
        static char *kwlist[] = {"voltage", "state", "action", "type", nullptr};
        if (!PyArg_ParseTupleAndKeywords(args, kwdict, "i|sss", kwlist, &voltage, &state, &action, &type)){
            return nullptr;
        }
        printf("-- This parrot wouldn't %s if you put %i Volts throught it.\n", action, voltage);
        printf("-- Lovely plumage, the %s -- It's %s\n", type, state);
        Py_RETURN_NONE;
    }

在模块的初始化函数中,我们需要将方法列表传递给python解释器。初始化函数必须以 initname() 命名,name是模块名称,并且不需要定义为 static。

  PyMODINIT_FUNC initdemo(void){
      (void) Py_InitModule("demo", MyDemoMethods);
  }

接着cmake常规编译。

模块调用

最后,就可以在Python脚本中调用我们写的扩展模块了。

# -*- coding: utf-8 -*-
import sys
sys.path.append("/home/wangran01/learncpp/pymodule/demo/cmake-build-debug-remote")
import demo
​
def main():
    print demo.addx(123, 456)
​
if __name__ == "__main__":
    main()

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值