无法使用Cython返回所需的数据类型

时间:2018-11-14 12:36:35

标签: python cython cythonize

我想构建一个函数,该函数可以返回六个“ R”字母加上六个“ B”字母的最常见排列,列表可能如下所示:

a = ['R'] * 6 + ['B'] * 6
random.shuffle(a)
shuffle = ''.join(a)
shuffle

输出:“ BRBRRRBBRBBR”

我想编写一个此函数的循环来模拟这些字符串的最常见分布。我确实用python写了一个for循环,它确实起作用了,但是在导入cython来加速该功能后,出了点问题,这是代码:

'''Python Code'''
import random
def random_loop_py(times):
    a = ['R'] * 6 + ['B'] * 6
    count = {}
    for i in range(times):
        random.shuffle(a)
        shuffle = ''.join(a)
        if shuffle in count.keys():
            count[shuffle] += 1
        else:
            count[shuffle] = 1
    return count
%timeit random_loop_py(100000)

'''Cython Code'''
    %load_ext cython
    %%cython
    import random
    cpdef void random_loop(int size):
        a = ['R'] * 6 + ['B'] * 6
        count = {}
        for i in range(size):
            random.shuffle(a)
            shuffle = ''.join(a)
            if shuffle in count.keys():
                count[shuffle] += 1
            else:
                count[shuffle] = 1
        return count.values()

错误:

Error compiling Cython file:
------------------------------------------------------------
...
        shuffle = ''.join(a)
        if shuffle in count.keys():
            count[shuffle] += 1
        else:
            count[shuffle] = 1
    return count.keys()
                    ^
------------------------------------------------------------

/Users/lee_excited/.ipython/cython/_cython_magic_e70ad62499224c5d4fd4e23d6dcb9e49.pyx:12:21: Return with value in void function
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-120-a09f2e5d5e69> in <module>
----> 1 get_ipython().run_cell_magic('cython', '', "import random\ncpdef void random_loop(int size):\n    a = ['R'] * 6 + ['B'] * 6\n    count = {}\n    for i in range(size):\n        random.shuffle(a)\n        shuffle = ''.join(a)\n        if shuffle in count.keys():\n            count[shuffle] += 1\n        else:\n            count[shuffle] = 1\n    return count.keys()\n")

~/anaconda3/lib/python3.6/site-packages/IPython/core/interactiveshell.py in run_cell_magic(self, magic_name, line, cell)
   2321             magic_arg_s = self.var_expand(line, stack_depth)
   2322             with self.builtin_trap:
-> 2323                 result = fn(magic_arg_s, cell)
   2324             return result
   2325 

<decorator-gen-127> in cython(self, line, cell)

~/anaconda3/lib/python3.6/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

~/anaconda3/lib/python3.6/site-packages/Cython/Build/IpythonMagic.py in cython(self, line, cell)
    323         if need_cythonize:
    324             extensions = self._cythonize(module_name, code, lib_dir, args, quiet=args.quiet)
--> 325             assert len(extensions) == 1
    326             extension = extensions[0]
    327             self._code_cache[key] = module_name

TypeError: object of type 'NoneType' has no len()

请问我应该返回什么样的数据来加快仿真速度?

1 个答案:

答案 0 :(得分:0)

您的函数具有void返回类型:

cpdef void random_loop(int size):
    ...
    return count.values()

因此,您不应从中返回任何内容,并且异常消息非常清楚。将返回类型更改为list

cpdef list random_loop(int size):
    ...
    return list(count.values())

P.S。

您的功能不是非常适合Cython:我认为您不会获得显着的性能改善。

更新

修复后,我无法重现您的错误

In [9]: %%cython
   ...: import random
   ...: cpdef list random_loop(int size):
   ...:     a = ['R'] * 6 + ['B'] * 6
   ...:     count = {}
   ...:     for i in range(size):
   ...:         random.shuffle(a)
   ...:         shuffle = ''.join(a)
   ...:         if shuffle in count.keys():
   ...:             count[shuffle] += 1
   ...:         else:
   ...:             count[shuffle] = 1
   ...:     return list(count.values())
   ...: 

In [10]: random_loop(10)
Out[10]: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

如您所见,它可以完美编译。