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

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

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

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

【问题讨论】:

    标签: python swig ctypes cython word-wrap


    【解决方案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?
    最近更新 更多