包中的 Cython 酸洗“未找到”错误

And*_*rew 5 python pickle cython

我在腌制 Cython 类时遇到问题,但仅当它在包中定义时。这个问题之前在网上提到,但他们没有说明它是如何解决的。这里有两个组件:使用__reduce__方法的 Cython 酸洗和包错误。

Cython 酸洗成功

我将首先展示它在没有包部分的情况下是如何工作的。这个例子工作正常。

Cython 文件

我的 Cython 文件是reudce.pyx

cdef class Foo(object):
    cdef int n

    def __init__(self, n):
        self.n = n

    def __reduce__(self):
        return Foo, (self.n,)
Run Code Online (Sandbox Code Playgroud)

安装文件

这可以编译为setup.py

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = [Extension("reduce", ["reduce.pyx"])]
)
Run Code Online (Sandbox Code Playgroud)

通过执行 python setup.py build && cp build/lib*/reduce.so .

测试脚本

测试脚本被调用test_reduce.py并且是:

import reduce
import pickle
f = reduce.Foo(4)
print pickle.dumps(f)
Run Code Online (Sandbox Code Playgroud)

执行python test_reduce.py工作正常。

封装失败中的 Cython 酸洗

但是,一旦reduce.pyx放入包中,就会出错。

包创建

要重现这一点,首先创建一个名为bar.

mkdir bar
mv reduce.so bar
echo "from reduce import Foo" > bar/__init__.py 
Run Code Online (Sandbox Code Playgroud)

测试脚本

test_reduce.py文件更改为:

import bar
import pickle
f = bar.Foo(4)
print pickle.dumps(f)
Run Code Online (Sandbox Code Playgroud)

错误信息

运行python test_reduce.py会出现以下错误:

File "/usr/lib/python2.7/pickle.py", line 286, in save
  f(self, obj) # Call unbound method with explicit self
File "/usr/lib/python2.7/pickle.py", line 748, in save_global
  (obj, module, name))
pickle.PicklingError: Can't pickle <type 'reduce.Foo'>: it's not found as reduce.Foo
Run Code Online (Sandbox Code Playgroud)

有一些错误都变成了 PicklingError 在pickle.py查看该代码后,发生的具体错误是:

ImportError: No module named reduce
Run Code Online (Sandbox Code Playgroud)

健全性测试

要检查是否存在某种范围或其他问题,如果我运行 pickle 模块应执行的步骤,则一切正常:

f = bar.Foo(4)
call, args = f.__reduce__()
print call(*args)
Run Code Online (Sandbox Code Playgroud)

所以这是怎么回事?!

And*_*rew 5

问题出在构建脚本中。该Pickle模块使用__module__函数/类的属性进行酸洗。该__module__属性来自脚本Extension()中构造函数的第一个参数setup.py。由于我将构造函数定义为Extension('reduce', ['reduce.pyx']),因此__module__属性为reduce。应该是bar/reduce这样,因为它现在是在一个包中。

使setup.py看起来像:

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = [Extension('bar/reduce', ['reduce.pyx'])]
)
Run Code Online (Sandbox Code Playgroud)

解决问题。