用于读取可变参数长度的 Python C 包装器

Posted

技术标签:

【中文标题】用于读取可变参数长度的 Python C 包装器【英文标题】:Python C wrapper for reading variable argument lengths 【发布时间】:2012-07-25 00:30:32 【问题描述】:

我正在尝试替换 MATLAB/MEX 并切换到 Python。我遇到了 SWIG、ctypes 和 Cython 作为可能的解决方案,并开始尝试 SWIG(这看起来很简单)。

我的 C 函数具有 main(int argc, char *argv[]) 形式的可变参数长度。我在网上找到了解决方案,但是与 SWIG 一起使用会导致很多问题。

    其他方法(ctypes / Cython)是否更简单? 使用 SWIG 完成此任务的任何示例都会有所帮助。

【问题讨论】:

【参考方案1】:

实际上有an example in the SWIG documentation 用于Python 的这种功能。我在这里引用了它,并稍作改动:

%typemap(in) (int argc, char *argv[]) 
  int i;
  if (!PyList_Check($input)) 
    PyErr_SetString(PyExc_ValueError, "Expecting a list");
    return NULL;
  
  $1 = PyList_Size($input);
  $2 = (char **) malloc(($1+1)*sizeof(char *));
  for (i = 0; i < $1; i++) 
    PyObject *s = PyList_GetItem($input,i);
    if (!PyString_Check(s)) 
        free($2);
        PyErr_SetString(PyExc_ValueError, "List items must be strings");
        return NULL;
    
    $2[i] = PyString_AsString(s);
  
  $2[i] = 0;


%typemap(freearg) (int argc, char *argv[]) 
   free($2); // If here is uneeded, free(NULL) is legal

这让你在 Python 中做的很简单:

import test
test.foo(["a", "b", "c"])

其中test 是您提供给 SWIG 的模块的名称,foo 是与签名 int argc, char *argv[] 匹配的函数。对 Python 程序员来说简单直观,它封装并重用了复杂的部分。


文档似乎没有提到的是,有一个接口文件已经为您完成了所有这些工作:

%module test

%include <argcargv.i>

%apply (int ARGC, char **ARGV)  (int argc, char *argv[]) 

void foo(int argc, char *argv[]);

足够了。

【讨论】:

谢谢,这个答案很完美!当我尝试使用@HYRY 的 ctypes 答案时,我会得到错误。是否可以使用 ctypes 代替 swig?我很好奇...:/ @BPL 你在sizeof(size_t) != sizeof(int) 的平台上吗?【参考方案2】:

这是一个使用 ctypes 的示例。

首先是c代码,不能改变argv的内容:

#include <stdio.h>
void test(int n, char *argv[])

    int i;
    for(i=0;i<n;i++)
    
        printf("%s\n", argv[i]);
    

那么就可以通过下面的python代码调用这个c函数了:

from ctypes import *
dll = cdll.LoadLibrary("charpp_test.dll") 
argv = ["test1", "testtest2", "testtesttest3"]
dll.test(len(argv), (c_char_p*len(argv))(*argv))

【讨论】:

谢谢。但是,如果我对 .c 文件进行任何更改并尝试使用 python 代码,则此更改不会反映。我试图在你的代码末尾“del dll”,但这没有帮助。如何卸载此 dll?

以上是关于用于读取可变参数长度的 Python C 包装器的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SWIG 包装带有可变参数的 C 函数

C ++:使用可变参数模板的类包装器

PHP:通过引用的可变长度参数列表?

Fortran中的可变长度参数列表?

用于可变长度参数数组的 PHPDoc

可变参数宏包装器,扩展为使用与参数数量相对应的字符格式化字符串