在C中实现一个简单的python函数是否很简单?

时间:2011-04-23 04:44:15

标签: python c for-loop ctypes

我正在研究这篇文章提出的问题:Fast way to remove a few items from a list/queue

基本上我想做的就是在C中实现for循环.for循环需要访问生成器并能够删除数组的元素(并递增整数)。我身上的东西告诉我这很难,但另一部分说它可以在几分钟内完成。

我没有编写高级C的经验(我为微控制器编写了代码),以及ctypes和其他c->的教程。 python似乎正在解决更棘手的问题。

def forfilt():
   marked = (i for i, x in enumerate(b) if tokeep(x))
   shift = 0
   for n in marked:
      del b[n - shift]
      shift += 1

我问两个问题:

  • 这很难吗?

  • 你有什么指针/想自己编写代码吗? :d

这实际上对我来说似乎是一个相当重要的问题。我不知道有什么方法可以快速完成原始问题的要求。我想如果你知道答案,那么问题就是无效。

3 个答案:

答案 0 :(得分:3)

如果您只需要删除for循环开销,那么在Cython(pip install cython)中定义for循环变量的类型就足够了。这是Cython remove_inplace_senderle2()中修改后的delitems.pyx

#cython: boundscheck=False, wraparound=False
import cython

@cython.locals(end=cython.Py_ssize_t, i=cython.Py_ssize_t)
def remove_inplace_senderle2(L, keep):
    end = 0
    for i in range(len(L)):
        x = L[end] = L[i]
        if keep(x):
           end += 1

    del L[end:]

for i in range(len(L))转换为经典的C循环:for (i=0; i < L_length; ++i),其开销与keep()的函数调用开销相形见绌。

注意:纯Python中的上述函数可能比L = filter(keep, L)(或listcomp)慢。

有关如何编译和使用Cython的简单示例,请参阅gcd() function

答案 1 :(得分:2)

这取决于简单是多么简单。是的,只要输入是数组,就可以将此特定函数写为就地内存移动。

size_t for_filt( my_struct *b, size_t n ) {
    my_struct *src_pen, *dst_pen;

    for ( src_pen = dst_pen = b;
          src_pen != b + n;
          ++ src_pen ) {
        if ( tokeep( src_pen ) ) {
            memmove( dst_pen ++, src_pen, sizeof (my_struct) );
        }
    }

    return dst_pen - b; /* return number of elements in resulting array */
}

C ++标准库将上述功能简化为单行:

n = std::remove_if( b, b+n, std::not1( tokeep ) ) - b;

该函数将使用除数组之外的结构,但n = … - b;是特定于数组的。

答案 2 :(得分:2)

针对CPython C-API编写C代码比在没有这种API支持的情况下编写C代码要愉快得多。然而,它主要是构建和链接过程并且完成所有设置,这可能相当繁琐。一旦你有一个C扩展,添加它并不太困难(虽然仍然有一些摆弄,以便在Python级别正确地暴露事物并确保所有引用计数都正确)。

像Cython这样的其他静态编译工具类似的设置成本相对较高,以使编译的扩展首先工作,但是一旦已经存在就更容易使用。

关于您的具体问题,通过将列表理解方法与filter内置(或其Py3k等效,functools.filter)进行比较,您链接的问题的海报已经证明了将循环代码放入C - native循环的效果是内置迭代和缩减函数的主要优点之一,如sumanyall,{{ 1}}和map

删除Python级别循环开销可能是两种方法(列表理解与过滤器调用)性能差异的大部分差异造成的。