Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C扩展中使用Python列表_Python_C - Fatal编程技术网

在C扩展中使用Python列表

在C扩展中使用Python列表,python,c,Python,C,我已经到了需要将类中的两个方法重写为C扩展以提高性能的地步(交叉、联合)。我的C语言背景非常有限,我从未为Python编写过扩展。在扩展中,我需要使用一个作为类属性的列表(self.table;它是一个列表和None对象的列表)。扩展名应该返回一个整数。所以,问题是,我如何将列表和无对象列表传递给C扩展并在那里读取它?先谢谢你 附言。 我需要一个自定义哈希表,因为我使用的是滚动哈希算法,这在Google知道的任何Python模块中都不存在 class HashTable: def __i

我已经到了需要将类中的两个方法重写为C扩展以提高性能的地步(交叉、联合)。我的C语言背景非常有限,我从未为Python编写过扩展。在扩展中,我需要使用一个作为类属性的列表(self.table;它是一个列表和None对象的列表)。扩展名应该返回一个整数。所以,问题是,我如何将列表和无对象列表传递给C扩展并在那里读取它?先谢谢你

附言。 我需要一个自定义哈希表,因为我使用的是滚动哈希算法,这在Google知道的任何Python模块中都不存在

class HashTable:
    def __init__(self, table_length, base):
        self.table_length = table_length
        self.base = base
        self.items = 0
        self.table = [None for _ in xrange(self.table_length)]

    def __iter__(self):
        return iter(self.table)

    def __getitem__(self, hash_value):
        return self.table[hash_value]

    def __len__(self):
        return self.items

    def __str__(self):
        return str(self.table)

    def insert(self, item, hash_value):
        if self.table[hash_value] is None:
            self.table[hash_value] = [item]
            self.items += 1
        else:
            if item not in self.table[hash_value]:
                self.table[hash_value].append(item)
                self.items += 1

    def intersection_len(self, table):
        if table.table_length != self.table_length or table.base != self.base:
            raise ValueError('Tables must have equal length and hash function base')
        result = 0
        for i, items in enumerate(table):
            if items is None or self.table[i] is None:
                continue
            for item in items:
                if item in self.table[i]:
                    result += 1
        return result

    def union_len(self, table):
        if table.table_length != self.table_length or table.base != self.base:
            raise ValueError('Tables must have equal length and hash function base')
        result = 0
        for i in xrange(self.table_length):
            if table[i] is None and self.table[i] is None:
                continue
            elif table[i] is None:
                result += len(self.table[i])
            elif self.table[i] is None:
                result += len(table[i])
            else:
                result += len(table[i])
                for item in table[i]:
                    if item not in self.table[i]:
                        result += 1
        return result

    def dump(self):
        for i in xrange(self.table_length):
            if self.table[i] is not None:
                self.table[i] = None`

为什么你认为用C语言重写这个算法会给你所需要的性能?(与此版本相比,您需要什么性能?)

我可能会从编写性能测试套件开始,然后使用Python原语(如
zip
)改进Python算法,而不是嵌套循环(
,用于xrange中的I(…)
),将CSE从循环中拉出,等等


在开始扩展之前,我将在pypy下运行改进的Python版本,以了解创建C扩展的预期效果。最后,如果需要一个扩展,我会在使用C之前研究Cython和Boost(因为Python扩展对于C来说是一个相当困难的学习过程——并且不可能给您提供运行速度快的东西)。

为Python构建C扩展的最简单方法是通过
setup.py
文件,例如:

from distutils.core import setup, Extension

lolan = Extension('lolan', sources = ['lolanmodule.c'])

setup (name = 'Example',
        version = '1.0',
        description = 'Just an exapmle',
        ext_modules = [lolan])
C代码本身可能类似于:

#include <Python.h>

static PyObject*
count_nones(PyObject* self, PyObject* args)
{
    PyObject* lol;

    if (!PyArg_ParseTuple(args, "O", &lol))
        return NULL;

    Py_ssize_t len = PySequence_Length(lol);
    int result = 0;
    for(Py_ssize_t i=0; i<len; ++i) {
        PyObject* item = PySequence_GetItem(lol, i);
        if(item==Py_None) ++result;
        Py_DECREF(item);
    }
    return Py_BuildValue("i", result);
}

static PyMethodDef LolanMethods[] =
{
     {"count_nones", count_nones, METH_VARARGS, "Count Nones."},
     {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC
initlolan(void)
{
     (void) Py_InitModule("lolan", LolanMethods);
}
(输出将根据您的平台而有所不同——这在MacOSX 10.9中)

然后,以交互方式进行尝试:

$ python
Python 2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import lolan
>>> l=[None]*3 + [[] for _ in range(4)]
>>> lolan.count_nones(l)
3
>>> lolan.count_nones(l*7)
21
>>> 
当然,您需要比这更好的单元测试,但这开始表明模块
lolan
中的函数
count\u nones
确实接受“列表和非列表”(模块名称缩写为:-),并计算参数项的数量
None


在这里,我重点介绍了在中介绍的“抽象级别”函数;对于某些类型约束,使用“具体级别”函数可能会获得稍好的性能,但这不会产生很大的影响。

随着列表大小的增加,在某些列表中使用
x会变得更慢。
操作中的
必须顺序读取列表中的每个项目,直到找到匹配项。我会尝试更改您的数据结构以使用集合列表

未经测试,但我认为唯一需要更改的代码是
insert()


我还没有详细研究过您想要加速的方法,但在这里我无能为力(例如,使用一个屏蔽数组来处理None值)?我假设您在这里的实际问题是您想要加速这两种方法;你考虑过Cython吗?@尽管我从未真正使用过Cython。如果我能用Cython保存这个类,用Python保存其余代码,那就太好了。将所有代码重写成Cython将花费大量时间。@GrayFall9,Cython非常容易使用。在玩了一段时间的代码之后,我发现scipy 2013的这一系列视频非常有用。我发现您在python中可以做的唯一改进似乎是更改
union\u len
。它似乎比交叉路口慢得多(在我的机器上慢6倍)。但是,只需将其重写为
return len(self)+len(other)-self,就可以显著提高
union\u len
的执行时间。intersection\u len(other)
集也应该使相交和并集方法更快。用于确定这些方法中的项数的for循环当前为O(n^2),成为一种更快的集合操作,例如
result+=len(table(i)&self.table(i))
。这使得情况稍微恶化(因为额外哈希计算的开销)。碰撞虽然存在,但非常罕见,因此比较两个子列表主要需要O(1)。尽管如此,我同意如果我的哈希函数产生更多的冲突,你的方法会更有用处。这会导致在内存中构建和删除大量新集合的巨大开销。构建这些集合是用C语言完成的,应该非常有效。听起来你期望的是一个稀疏的数据集,这确实让事情变得很不一样。我尝试了izip,结果有了一点小小的改进。问题是我需要比较50万个哈希表。这就是为什么我需要更快的东西。看来我应该和Cython一起去。非常感谢您的帮助。我倾向于同意Bjorn…如果不先使用内置的更好的算法,我不会放弃纯Python解决方案。其中很多都是用C语言编写的。如果您可以更改算法,另一种可能是取决于您的硬件以及您正在做的事情。您似乎忽略了对任何嵌套列表的访问——可能是因为您认为从您提供的内容可以明显看出这一点。这有很大帮助。谢谢。很高兴听到,@GrayFall9--那么也许你可以接受答案?@martineau,我发布的代码显示,给定一个
PyObject*x
这是一个列表,
PySequence\u Length(o)
给你它的长度,
PySequence\u GetItem(o,I)
给你
PyObject*
这是它的
I
第项(当你完成它时,你必须
Py_DECREF
)。这适用于无论你如何获得
o
,例如,如果它是作为另一个列表项获得的列表,它也适用。考虑到所有这些,似乎“嵌套列表”没有任何神秘之处,是吗?-)取决于具体的数据结构和需求,以及C或C++是否实际使用。例如,C++的
std::vector
通常比Python的
list
优秀;但是Python的
dict
$ python
Python 2.7.5 (default, Mar  9 2014, 22:15:05) 
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.0.68)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import lolan
>>> l=[None]*3 + [[] for _ in range(4)]
>>> lolan.count_nones(l)
3
>>> lolan.count_nones(l*7)
21
>>> 
def insert(self, item, hash_value):
    if self.table[hash_value] is None:
        self.table[hash_value] = set()
    self.table[hash_value].add(item)
    self.items += 1