我被告知,由于使用DefaultDict
需要Python对象类型声明,以下扩展类型可能不是很有效。有人能解释为什么会这样吗?DefaultDict
是否仍然值得使用(而不是dict
)?
cdef class CythonClass(object):
cdef int var1, var2
cdef object defaultdict
def __init__(self, a, b):
self.var1 = a
self.var2 = b
self.defaultdict = DefaultDict(DefaultDict([]))
我可能在另一个答案中夸大了效率部分。我的意思是:当你必须使用Python对象时,不要期望巨大的加速(超过1.5-2倍)。
你可以使用它们,而且不会比在python代码中使用它们慢(除了极少数情况)。然而,Cython的强大之处在于,您可以使用原生c类型和同构数据结构,如c数组(这可能比python列表甚至字典快得多),或者如果您使用c++,也可以使用vector
、unordered_map
等。
处理Python对象时需要记住的一点是,所有Python对象都是指向某些结构的指针,因此每个对象都添加了一层间接层-对于Pythonint
s也是如此。然而,Cythonint
是一个没有间接层的C整数。这就是为什么Cython中的for
-循环要快得多的主要原因之一。(然而,它们被限制在64位的范围内,而不是像Python中那样精度无限,这是一种权衡)。
另一点是,对python对象进行操作意味着您需要进行python查找、python操作等。然而,对于内置对象,cython可以使用python C API来避免基于python的查找,从而获得额外的速度(我猜DefaultDict
不在其中),例如,对于声明的dicts,以下代码的编译方式不同:
def dumb_func(dict dct, str key):
return dct[key] # translates to: __Pyx_PyDict_GetItem(__pyx_v_dct, __pyx_v_key)
def dumb_func(object dct, object key): # different signature
return dct[key] # translates to: PyObject_GetItem(__pyx_v_dct, __pyx_v_key)
您可能会猜测哪一个更快,是直接寻址dict的(__Pyx_PyDict_GetItem
可能是PyDict_GetItem
和PyDict_GetItemString
的复杂包装器),还是只使用PyObject_GetItem
寻址python对象的(通过python查找)。这也不会是一个巨大的加速,但它是值得注意的。
最后,我要说的是,在Cython代码中,正常(和声明的)dict
s显然比DefaultDict
快(除了一些C或C++类)。