热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

PythonExtensionProgrammingwithC

http:www.tutorialspoint.compythonpython_further_extensions.htmAnycodethatyouwriteusinganyc

http://www.tutorialspoint.com/python/python_further_extensions.htm


Any code that you write using any compiled language like C, C++ or Java can be integrated or imported into another Python script. This code is considered as an "extension."

A Python extension module is nothing more than a normal C library. On Unix machines, these libraries usually end in .so (for shared object). On Windows machines, you typically see .dll (for dynamically linked library).

Pre-Requisite:

To start writing your extension, you are going to need the Python header files.

  • On Unix machines, this usually requires installing a developer-specific package such as python2.5-dev.

  • Windows users get these headers as part of the package when they use the binary Python installer.

Additionally, it is assumed that you have good knowledge of C or C++ to write any Python Extension using C programming.

First look at a Python extension:

For your first look at a Python extension module, you'll be grouping your code into four parts:

  • The header file Python.h.

  • The C functions you want to expose as the interface from your module.

  • A table mapping the names of your functions as Python developers will see them to C functions inside the extension module.

  • An initialization function.

The header file Python.h

Start including Python.h header file in your C source file, which will give you access to the internal Python API used to hook your module into the interpreter.

Be sure to include Python.h before any other headers you might need. You'll follow the includes with the functions you want to call from Python.

The C functions:

The signatures of the C implementations of your functions will always take one of the following three forms:

staticPyObject *MyFunction(PyObject*self,PyObject*args );

staticPyObject *MyFunctionWithKeywords(PyObject*self,PyObject*args,PyObject*kw);

staticPyObject *MyFunctionWithNoArgs(PyObject*self);

Each one of the preceding declarations returns a Python object. There's no such thing as a void function in Python as there is in C. If you don't want your functions to return a value, return the C equivalent of Python's None value. The Python headers define a macro, Py_RETURN_NONE, that does this for us.

The names of your C functions can be whatever you like as they will never be seen outside of the extension module. So they would be defined as static function.

Your C functions usually are named by combining the Python module and function names together, as shown here:

staticPyObject*module_func(PyObject*self,PyObject*args){/* Do your stuff here. */Py_RETURN_NONE;}

This would be a Python function called func inside of the module module. You'll be putting pointers to your C functions into the method table for the module that usually comes next in your source code.

The method mapping table:

This method table is a simple array of PyMethodDef structures. That structure looks something like this:

structPyMethodDef{char*ml_name;PyCFunction ml_meth;int ml_flags;char*ml_doc;};

Here is the description of the members of this structure:

  • ml_name: This is the name of the function as the Python interpreter will present it when it is used in Python programs.

  • ml_meth: This must be the address to a function that has any one of the signatures described in previous seection.

  • ml_flags: This tells the interpreter which of the three signatures ml_meth is using.

    • This flag will usually have a value of METH_VARARGS.

    • This flag can be bitwise or'ed with METH_KEYWORDS if you want to allow keyword arguments into your function.

    • This can also have a value of METH_NOARGS that indicates you don't want to accept any arguments.

  • ml_doc: This is the docstring for the function, which could be NULL if you don't feel like writing one

This table needs to be terminated with a sentinel that consists of NULL and 0 values for the appropriate members.

EXAMPLE:

For the above-defined function, we would have following method mapping table:

staticPyMethodDefmodule_methods[]=
{

{"func",(PyCFunction)module_func, METH_NOARGS, NULL },

{ NULL, NULL,0, NULL
}

};

The initialization function:

The last part of your extension module is the initialization function. This function is called by the Python interpreter when the module is loaded. It's required that the function be named initModule, where Moduleis the name of the module.

The initialization function needs to be exported from the library you'll be building. The Python headers define PyMODINIT_FUNC to include the appropriate incantations for that to happen for the particular environment in which we're compiling. All you have to do is use it when defining the function.

Your C initialization function generally has the following overall structure:

PyMODINIT_FUNC initModule(){Py_InitModule3(func,module_methods,"docstring...");}

Here is the description of Py_InitModule3 function:

  • func: This is the function to be exported.

  • module_methods: This is the mapping table name defined above.

  • docstring: This is the comment you want to give in your extension.

Putting this all together looks like the following:

#include 

static PyObject *module_func(PyObject *self, PyObject *args) {
   /* Do your stuff here. */
   Py_RETURN_NONE;
}

static PyMethodDef module_methods[] = {
   { "func", (PyCFunction)module_func, METH_NOARGS, NULL },
   { NULL, NULL, 0, NULL }
};

PyMODINIT_FUNC initModule() {
   Py_InitModule3(func, module_methods, "docstring...");
}

 

EXAMPLE:

A simple example that makes use of all the above concepts:

 

#include 

static PyObject* helloworld(PyObject* self)
{
return Py_BuildValue("s", "Hello, Python extensions!!");
}

static char helloworld_docs[] =
"helloworld( ): Any message you want to put here!!\n";

static PyMethodDef helloworld_funcs[] = {
{"helloworld", (PyCFunction)helloworld,
METH_NOARGS, helloworld_docs},
{NULL}
};

void inithelloworld(void)
{
Py_InitModule3("helloworld", helloworld_funcs,
"Extension module example!");

}

 

Here the Py_BuildValue function is used to build a Python value. Save above code in hello.c file. We would see how to compile and install this module to be called from Python script.

Building and Installing Extensions:

The distutils package makes it very easy to distribute Python modules, both pure Python and extension modules, in a standard way. Modules are distributed in source form and built and installed via a setup script usually called setup.py as follows.

For the above module, you would have to prepare following setup.py script:

from distutils.core import setup,Extension
setup(name='helloworld', version='1.0',  \
      ext_modules=[Extension('helloworld',['hello.c'])])

Now, use the following command, which would perform all needed compilation and linking steps, with the right compiler and linker commands and flags, and copies the resulting dynamic library into an appropriate directory:

$ python setup.py install

On Unix-based systems, you'll most likely need to run this command as root in order to have permissions to write to the site-packages directory. This usually isn't a problem on Windows

Import Extensions:

Once you installed your extension, you would be able to import and call that extension in your Python script as follows:

#!/usr/bin/pythonimport helloworld

print helloworld.helloworld()

This would produce the following result:

Hello,Python extensions!!

Passing Function Parameters:

Because you'll most likely want to define functions that do accept arguments, you can use one of the other signatures for your C functions. For example, following function, that accepts some number of parameters, would be defined like this:

staticPyObject * module_func(PyObject*self,PyObject*args){/* Parse args and do something interesting here. */Py_RETURN_NONE;}

The method table containing an entry for the new function would look like this:

static PyMethodDef module_methods[]=
{

{"func",(PyCFunction)module_func, METH_NOARGS, NULL },

{"func",module_func, METH_VARARGS, NULL },

{ NULL, NULL,0, NULL }

};

You can use API PyArg_ParseTuple function to extract the arguments from the one PyObject pointer passed into your C function.

The first argument to PyArg_ParseTuple is the args argument. This is the object you'll be parsing. The second argument is a format string describing the arguments as you expect them to appear. Each argument is represented by one or more characters in the format string as follows.

static PyObject *module_func(PyObject *self, PyObject *args) {
int i;
double d;
char *s;

if (!PyArg_ParseTuple(args, "ids", &i, &d, &s)) {
return NULL;
}

/* Do something interesting here. */
Py_RETURN_NONE;
}

 

 

Compiling the new version of your module and importing it will enable you to invoke the new function with any number of arguments of any type:

module.func(1, s="three", d=2.0)
module.func(i=1, d=2.0, s="three")

module.func(s="three", d=2.0, i=1)

You can probably come up with even more variations.

The PyArg_ParseTuple Function:

Here is the standard signature for PyArg_ParseTuple function:

intPyArg_ParseTuple(PyObject* tuple,char* format,...)

This function returns 0 for errors, and a value not equal to 0 for success. tuple is the PyObject* that was the C function's second argument. Here format is a C string that describes mandatory and optional arguments.

Here is a list of format codes for PyArg_ParseTuple function:

Code C type Meaning
c char A Python string of length 1 becomes a C char.
d double A Python float becomes a C double.
f float A Python float becomes a C float.
i int A Python int becomes a C int.
l long A Python int becomes a C long.
L long long A Python int becomes a C long long
O PyObject* Gets non-NULL borrowed reference to Python argument.
s char* Python string without embedded nulls to C char*.
s# char*+int Any Python string to C address and length.
t# char*+int Read-only single-segment buffer to C address and length.
u Py_UNICODE* Python Unicode without embedded nulls to C.
u# Py_UNICODE*+int Any Python Unicode C address and length.
w# char*+int Read/write single-segment buffer to C address and length.
z char* Like s, also accepts None (sets C char* to NULL).
z# char*+int Like s#, also accepts None (sets C char* to NULL).
(...) as per ... A Python sequence is treated as one argument per item.
|   The following arguments are optional.
:   Format end, followed by function name for error messages.
;   Format end, followed by entire error message text.

Returning Values:

Py_BuildValue takes in a format string much like PyArg_ParseTuple does. Instead of passing in the addresses of the values you're building, you pass in the actual values. Here's an example showing how to implement an add function:

staticPyObject * foo_add(PyObject*self,PyObject*args)

{int a;

int b;

if(!PyArg_ParseTuple(args,"ii",&a,&b))

{return NULL;}

returnPy_BuildValue("i", a + b);}

This is what it would look like if implemented in Python:

def add(a, b):return(a + b)

You can return two values from your function as follows, this would be cauptured using a list in Python.

staticPyObject * foo_add_subtract(PyObject*self,PyObject*args)

{int a;int b;

if(!PyArg_ParseTuple(args,"ii",&a,&b)){return NULL;}

returnPy_BuildValue("ii", a + b, a - b);}

This is what it would look like if implemented in Python:

def add_subtract(a, b):return(a + b, a - b)

The Py_BuildValue Function:

Here is the standard signature for Py_BuildValue function:

PyObject*Py_BuildValue(char* format,...)

Here format is a C string that describes the Python object to build. The following arguments ofPy_BuildValue are C values from which the result is built. The PyObject* result is a new reference.

Following table lists the commonly used code strings, of which zero or more are joined into string format.

Code C type Meaning
c char A C char becomes a Python string of length 1.
d double A C double becomes a Python float.
f float A C float becomes a Python float.
i int A C int becomes a Python int.
l long A C long becomes a Python int.
N PyObject* Passes a Python object and steals a reference.
O PyObject* Passes a Python object and INCREFs it as normal.
O& convert+void* Arbitrary conversion
s char* C 0-terminated char* to Python string, or NULL to None.
s# char*+int C char* and length to Python string, or NULL to None.
u Py_UNICODE* C-wide, null-terminated string to Python Unicode, or NULL to None.
u# Py_UNICODE*+int C-wide string and length to Python Unicode, or NULL to None.
w# char*+int Read/write single-segment buffer to C address and length.
z char* Like s, also accepts None (sets C char* to NULL).
z# char*+int Like s#, also accepts None (sets C char* to NULL).
(...) as per ... Builds Python tuple from C values.
[...] as per ... Builds Python list from C values.
{...} as per ... Builds Python dictionary from C values, alternating keys and values.

Code {...} builds dictionaries from an even number of C values, alternately keys and values. For example, Py_BuildValue("{issi}",23,"zig","zag",42) returns a dictionary like Python's {23:'zig','zag':42}.

 


推荐阅读
  • 欢乐的票圈重构之旅——RecyclerView的头尾布局增加
    项目重构的Git地址:https:github.comrazerdpFriendCircletreemain-dev项目同步更新的文集:http:www.jianshu.comno ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • 本文介绍了响应式页面的概念和实现方式,包括针对不同终端制作特定页面和制作一个页面适应不同终端的显示。分析了两种实现方式的优缺点,提出了选择方案的建议。同时,对于响应式页面的需求和背景进行了讨论,解释了为什么需要响应式页面。 ... [详细]
  • 本文分析了Wince程序内存和存储内存的分布及作用。Wince内存包括系统内存、对象存储和程序内存,其中系统内存占用了一部分SDRAM,而剩下的30M为程序内存和存储内存。对象存储是嵌入式wince操作系统中的一个新概念,常用于消费电子设备中。此外,文章还介绍了主电源和后备电池在操作系统中的作用。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • Linux服务器密码过期策略、登录次数限制、私钥登录等配置方法
    本文介绍了在Linux服务器上进行密码过期策略、登录次数限制、私钥登录等配置的方法。通过修改配置文件中的参数,可以设置密码的有效期、最小间隔时间、最小长度,并在密码过期前进行提示。同时还介绍了如何进行公钥登录和修改默认账户用户名的操作。详细步骤和注意事项可参考本文内容。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 如何用JNI技术调用Java接口以及提高Java性能的详解
    本文介绍了如何使用JNI技术调用Java接口,并详细解析了如何通过JNI技术提高Java的性能。同时还讨论了JNI调用Java的private方法、Java开发中使用JNI技术的情况以及使用Java的JNI技术调用C++时的运行效率问题。文章还介绍了JNIEnv类型的使用方法,包括创建Java对象、调用Java对象的方法、获取Java对象的属性等操作。 ... [详细]
author-avatar
静待花开0088
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有