假如我们要用C语言实现下面的python脚本bird.py

import os

def fly(name):
print(name + " is flying.\n")

调用脚本main.py

import bird

bird.fly("fwd")

执行效果如下

> python main.py
fwd is flying.

实现相同逻辑的原始C代码bird.c

#include <stdio.h>

void fly(const char *name)
{
printf("%s is flying.\n", name);
}

下面我们要将原始C代码改造成可以被main.py的python模块:

  • 包含头文件Python.h
  • 添加C函数fly的Python调用版本bird_fly
  • 添加向Python呈现C函数的方法表bird_methods
  • 添加模块初始化函数initbird(当动态库被python解释器搜索到时调用的函数)
#include <Python.h>
#include <stdio.h> void fly(const char *name)
{
printf("%s is flying.\n", name);
} static PyObject *bird_fly(PyObject *self, PyObject *args)
{
const char *name;
if (!PyArg_ParseTuple(args, "s", &name))
return NULL;
fly(name); Py_INCREF(Py_None);
return Py_None;
} static PyMethodDef bird_methods[] = {
{ "fly", bird_fly, METH_VARARGS, "Bird fly" },
{ NULL, NULL, 0, NULL }
}; PyMODINIT_FUNC initbird(void)
{
PyImport_AddModule("bird");
Py_InitModule("bird", bird_methods);
}

Linux下编译

# yum install -y python-devel
# gcc -o bird.so `python-config --cflags` `python-config --libs` -shared bird.c
### 将main.py和bird.so放置在同一目录下
# python main.py
fwd is flying.

Windows下编译

VS2017(只需安装python2.7的64位版本即可,本地开发工具可不装)下创建空项目bird,然后添加源文件bird.cpp(内容同bird.c),项目配置如下:

Tab 属性
常规 常规 > 目标名称 将此字段设置为与 Python 看到的模块名称完全匹配。
常规 常规 > 目标扩展名 .pyd
常规 项目默认值 > 配置类型 动态库(.dll)
C/C++ > 常规 附加包含目录 根据相应的安装添加 Python include 文件夹,例如 C:\Python27amd64\include
C/C++ > 预处理器 预处理器定义 在字符串的开头添加 Py_LIMITED_API;,可限制可从 Python 调用的某些函数,并使代码在 Python 不同版本之间更易于移植。
C/C++ > 代码生成 运行库 多线程 DLL (/MD)(请参阅下面的“警告”)
链接器 > 常规 附加库目录 根据相应的安装添加包含 .lib 文件的 Python libs 文件夹,例如 C:\Python27amd64\libs。 (务必指向包含 .lib文件的 libs 文件夹,而非包含 .py 文件的 Lib 文件夹。)
### 记住选择release + x64编译模式,否则编译dll会报错,然后将main.py和bird.pyd放置在同一目录下
bird\x64\Release> python main.py
fwd is flying.

参考文档

创建适用于 Python 的 C++ 扩展

使用C/C++代码编写Python模块的更多相关文章

  1. VS2012 编译带有c/c++代码的python模块失败解决方案

    python2.7默认编译带有/c++代码的模块/包是使用VS2008环境变量,所以为了可用,我们要在编译前设置环境变量 SET VS90COMNTOOLS=%VS110COMNTOOLS% 但有时只 ...

  2. 扩展Python模块系列(一)----开发环境配置

    本系列将介绍如何用C/C++扩展Python模块,使用C语言编写Python模块,添加到Python中作为一个built-in模块.Python与C之间的交互目前有几种方案: 1. 原生的Python ...

  3. 编写高质量代码--改善python程序的建议(八)

    原文发表在我的博客主页,转载请注明出处! 建议四十一:一般情况下使用ElementTree解析XML python中解析XML文件最广为人知的两个模块是xml.dom.minidom和xml.sax, ...

  4. python模块之sys和subprocess以及编写简单的主机扫描脚本

    python模块之sys和subprocess以及编写简单的主机扫描脚本 1.sys模块 sys.exit(n)  作用:执行到主程序末尾,解释器自动退出,但是如果需要中途退出程序,可以调用sys.e ...

  5. Python代码编写规范

    Python代码编写规范 编码: a)     如无特殊情况,文件一律使用UTF-8编码 b)     如无需特殊情况,文件头部必须加入#-*-coding:utf-8-*- 缩进 a)     统一 ...

  6. python的单元测试代码编写流程

    单元测试: 单元测试是对单独的代码块分别进行测试, 以确保它们的正确性, 单元测试主要还是由开发人员来做, 其余的集成测试和系统测试由专业的测试人员来做. python的单元测试代码编写主要记住以下几 ...

  7. 编写高质量代码--改善python程序的建议(七)

    原文发表在我的博客主页,转载请注明出处! 建议三十四:掌握字符串的基本用法 编程有两件事,一件是处理数值,另一件是处理字符串,在商业应用编程来说,处理字符串的代码超过八成,所以需要重点掌握. 首先有个 ...

  8. 编写高质量代码--改善python程序的建议(四)

    原文发表在我的博客主页,转载请注明出处! 建议十八:有节制的使用from...import语句 python提供了三种方式引入外部模块: import语句 from...import... __imp ...

  9. 编写高质量代码--改善python程序的建议(三)

    原文发表在我的博客主页,转载请注明出处! 建议十三:警惕eval()的安全漏洞 相信经常处理文本数据的同学对eval()一定是欲罢不能,他的使用非常简单: eval("1+1==2" ...

随机推荐

  1. Java面试(三)

    1  java中Exception 和 Error 区别 都是Throwable的子类.RuntimeException继承自Exception. Error和RuntimeException及其子类 ...

  2. jQuery使用toggle()方法进行显示隐藏

    转自:https://www.cnblogs.com/sosoft/p/3460556.html 这是一个示例: 1 <html> 2 <head> 3 <script ...

  3. Oracle11g-BBED安装

    oracle 11g中缺bbed包 下载地址: https://pan.baidu.com/s/19DVvIajarDjnynILNwQDWQ 密码:tmqt 1.BBED的安装 1.上传(sbbdp ...

  4. 虚拟机之 LNMP

    LNMP就是Linux nginx mysql php 一.mysql 下载安装mysql转至 LAMP (点击“LAMP”即可跳转) 也可以从快照跳转至mysql安装ok 二.php 下载同上, 1 ...

  5. 尝试在centos5下运行phantomjs2

    在redhat5上运行plantomjs 2,出现如下错误 bin/phantomjs: /lib64/libz.so.1: no version information available (req ...

  6. Python之面向过程和面向对象的区别

    一.面向过程 1.面向过程:核心是过程二字,过程指的是解决问题的步骤,好比如设计一条流水线,是一种机械式的思维方式. 就是程序从上到下一步步执行,一步步从上到下,从头到尾的解决问题 .基本设计思路就是 ...

  7. 【原创】11. MYSQL++ 之 Quoting 与 Escaping

    1. 综述 其实一看到这两个单词的时候我有点莫名其妙,可能英语没有学好,我的理解就是quoting是“引用”的意思,而Escaping是“逃脱”的意思.后来在看到了作者的TUTORIAL之后才大致明白 ...

  8. 安装gdb insight(6.8.1)

    如果之前安装过6.8或其它版本,请先删除以下目录 rm -rf /usr/local/insight rm -rf /usr/share/tcltk 如果之前设置过环境变量,也请删除 unset TC ...

  9. Jmeter调度器配置

    Jmeter的线程组设置里有一个调配器设置,用于设置该线程组下脚本执行的开始时间.结束时间.持续时间及启动延迟时间.当需要半夜执行性能测试时会用到这个功能. ps:设置调度器配置,需要将前面的循环次数 ...

  10. XP下,移动窗口产生重影的问题

    最近做了一个东西,其中有一个小窗口需要跟着主窗口一起移动,结果发现在Xp系统上总是产生重影,需要刷新桌面才能消失. 移动窗口我使用的是MoveWindow,最后一个参数bRepaint传递的是FALS ...