Python 调用 C 和 C 调用 Python 方法

在这篇博客中,我们将探讨如何在 Python 中调用 C 函数,以及如何在 C 中调用 Python 函数。利用这两种方法,你可以在项目中充分发挥 Python 的简洁性和 C 的高性能优势。

目录

  1. [Python 调用 C 函数](#Python 调用 C 函数)
    • [使用 ctypes](#使用 ctypes)
    • [使用 Cython](#使用 Cython)
  2. [C 调用 Python 函数](#C 调用 Python 函数)
    • [使用 Python C API](#使用 Python C API)

Python 调用 C 函数

使用 ctypes

ctypes 是 Python 的一个外部函数库,允许调用动态链接库(DLL 或共享库)的函数。

例子:简单的 C 函数

首先,我们编写一个简单的 C 函数,并将其编译成共享库。

hello.c

c 复制代码
#include <stdio.h>

void say_hello(const char* name) {
    printf("Hello, %s!\n", name);
}

编译这个 C 文件生成共享库:

bash 复制代码
gcc -shared -o libhello.so -fPIC hello.c

然后,我们使用 ctypes 在 Python 中调用这个 C 函数。

call_hello.py

python 复制代码
import ctypes

# 加载共享库
lib = ctypes.CDLL('./libhello.so')

# 定义函数原型
lib.say_hello.argtypes = [ctypes.c_char_p]
lib.say_hello.restype = None

# 调用 C 函数
lib.say_hello(b"World")

使用 Cython

Cython 是一种使得 C 代码可以无缝集成到 Python 的工具。它允许你在 Python 代码中嵌入 C 代码,从而提升性能。

例子:简单的 C 函数

我们编写一个简单的 Cython 文件。

hello.pyx

cython 复制代码
cdef extern from "hello.h":
    void say_hello(const char* name)

def call_hello(name):
    say_hello(name.encode('utf-8'))

编写一个 C 头文件。

hello.h

c 复制代码
void say_hello(const char* name);

编写一个 C 文件。

hello.c

c 复制代码
#include <stdio.h>
#include "hello.h"

void say_hello(const char* name) {
    printf("Hello, %s!\n", name);
}

编写一个 setup 文件来编译 Cython 代码。

setup.py

python 复制代码
from setuptools import setup
from setuptools.extension import Extension
from Cython.Build import cythonize

extensions = [
    Extension("hello", ["hello.pyx", "hello.c"])
]

setup(
    ext_modules=cythonize(extensions)
)

编译 Cython 代码:

bash 复制代码
python setup.py build_ext --inplace

编写一个 Python 文件调用 Cython 代码。

call_hello.py

python 复制代码
import hello

hello.call_hello("World")

C 调用 Python 函数

使用 Python C API

Python 提供了一个 C API,使得 C 代码可以嵌入到 Python 中。

例子:调用 Python 函数

首先,我们编写一个简单的 Python 函数。

script.py

python 复制代码
def greet(name):
    return f"Hello, {name}!"

然后,我们编写一个 C 文件来调用这个 Python 函数。

call_python.c

c 复制代码
#include <Python.h>

int main(int argc, char *argv[]) {
    // 初始化 Python 解释器
    Py_Initialize();

    // 添加当前目录到模块搜索路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('.')");

    // 导入 Python 脚本
    PyObject *pName = PyUnicode_DecodeFSDefault("script");
    PyObject *pModule = PyImport_Import(pName);
    Py_DECREF(pName);

    if (pModule != NULL) {
        // 获取函数
        PyObject *pFunc = PyObject_GetAttrString(pModule, "greet");

        if (PyCallable_Check(pFunc)) {
            // 创建参数
            PyObject *pArgs = PyTuple_Pack(1, PyUnicode_FromString("World"));

            // 调用函数
            PyObject *pValue = PyObject_CallObject(pFunc, pArgs);
            Py_DECREF(pArgs);

            if (pValue != NULL) {
                printf("Result of call: %s\n", PyUnicode_AsUTF8(pValue));
                Py_DECREF(pValue);
            } else {
                Py_DECREF(pFunc);
                Py_DECREF(pModule);
                PyErr_Print();
                fprintf(stderr, "Call failed\n");
                return 1;
            }
        } else {
            if (PyErr_Occurred())
                PyErr_Print();
            fprintf(stderr, "Cannot find function \"greet\"\n");
        }
        Py_XDECREF(pFunc);
        Py_DECREF(pModule);
    } else {
        PyErr_Print();
        fprintf(stderr, "Failed to load \"script\"\n");
        return 1;
    }

    // 结束 Python 解释器
    Py_Finalize();

    return 0;
}

编译并运行这个 C 文件:

bash 复制代码
gcc -o call_python call_python.c -I/usr/include/python3.8 -lpython3.8
./call_python

结论

在这篇博客中,我们展示了如何在 Python 中调用 C 函数,以及如何在 C 中调用 Python 函数。通过这两种方法,可以在项目中利用 Python 的简洁性和 C 的高性能优势。希望这篇教程对你有所帮助!

复制代码
相关推荐
m0_59640637几秒前
CSS如何高效引入样式表_对比link标签与import指令的性能差异
jvm·数据库·python
MoonBit月兔9 分钟前
MoonBit 大型软件合成挑战赛决赛暨 Meetup 0.9 版本专场回顾
大数据·开发语言·人工智能·moonbit
宣宣猪的小花园.17 分钟前
C语言重难点全解析:指针到内存四区
c语言·开发语言
南宫萧幕17 分钟前
HEV 智能能量管理实战:从 MPC/PPO 理论解析到 Python-Simulink 联合仿真闭环全流程
开发语言·python·算法·matlab·控制
码农的神经元19 分钟前
Python 实现县域变电站智能巡检与抢修调度:地图、路径规划与恢复策略
开发语言·python
我命由我1234533 分钟前
Java 开发 - CountDownLatch 不需要手动关闭
android·java·开发语言·jvm·kotlin·android studio·android-studio
谭欣辰1 小时前
详细讲解 C++ 状压 DP
开发语言·c++·动态规划
weixin_568996061 小时前
c++如何实现日志文件的异步落盘功能_基于无锁队列方案【附代码】
jvm·数据库·python
chaofan9801 小时前
GPT-5.5 全压力测试:为什么 API 聚合调度是解决“首字延迟”的技术关键?
开发语言·人工智能·python·gpt·自动化·api
才兄说1 小时前
机器人二次开发机器人动作定制?定制化舞蹈
python