我在选择Cython类时遇到麻烦,但仅限于在包中定义它时。这个问题被记录为previously online,但是他们没有说明如何解决。这里有两个组件:使用__reduce__
方法的Cython pickle 和包装错误。
Cython pickle 成功
我将首先展示它在没有包装部分的情况下是如何工作的。此示例正常工作。
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,)
设定档
这可以用
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"])]
)
通过执行
python setup.py build && cp build/lib*/reduce.so .
测试脚本
测试脚本称为
test_reduce.py
,它是:import reduce
import pickle
f = reduce.Foo(4)
print pickle.dumps(f)
执行
python test_reduce.py
可以正常工作。Cython pickle 中的包装失败
但是,一旦将
reduce.pyx
放入包装中,就会出现错误。包装制作
要重现此内容,请首先创建一个名为
bar
的包。mkdir bar
mv reduce.so bar
echo "from reduce import Foo" > bar/__init__.py
测试脚本
将
test_reduce.py
文件更改为:import bar
import pickle
f = bar.Foo(4)
print pickle.dumps(f)
错误信息
运行
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
在
pickle.py
中有很多错误都变成了PicklingError在查看该代码后,正在发生的特定错误是:ImportError: No module named reduce
健全性测试
要检查是否没有某种范围或其他问题,如果我运行pickle模块应执行的步骤,则一切正常:
f = bar.Foo(4)
call, args = f.__reduce__()
print call(*args)
那这是怎么回事?!
最佳答案
问题出在构建脚本中。 Pickle
模块使用函数/类的__module__
属性进行 pickle 。该__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'])]
)
解决了问题。