[英]Cython Pickling in Package “not found as” Error
我在挑選一個Cython類時遇到了麻煩,但只有當它在一個包中定義時才會出現問題。 之前在線注意到了這個問題,但他們沒有說明它是如何解決的。 這里有兩個組件:使用__reduce__
方法的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
工作正常。
但是,一旦將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
錯誤在pickle.py
變成了pickle.py
。查看該代碼后,發生的具體錯誤是:
ImportError: No module named reduce
要檢查是否存在某種范圍或其他問題,如果我運行pickle模塊應執行的步驟,一切正常:
f = bar.Foo(4)
call, args = f.__reduce__()
print call(*args)
那么這里發生了什么?!
問題出在構建腳本中。 Pickle
模塊使用函數/類的__module__
屬性進行酸洗。 __module__
屬性來自setup.py
腳本中Extension()
構造函數的第一個參數。 由於我將構造函數定義為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'])]
)
解決了這個問題。
編輯
也許這樣的事情是可能的: Foo.__module__ = 'bar.reduce'
在bar/__init__.py
或者您可以使用模塊copyreg
。 以下是copyreg代碼中的一些片段:
"""Helper to provide extensibility for pickle.
This is only useful to add pickle support for extension types defined in
C, not for instances of user-defined classes.
"""
def pickle(ob_type, pickle_function, constructor_ob=None):
# ...
# Example: provide pickling support for complex numbers.
try:
complex
except NameError:
pass
else:
def pickle_complex(c):
return complex, (c.real, c.imag)
pickle(complex, pickle_complex, complex)
舊版
Pickle這樣做:
try:
__import__(module, level=0)
mod = sys.modules[module]
klass = getattr(mod, name)
except (ImportError, KeyError, AttributeError):
raise PicklingError(
"Can't pickle %r: it's not found as %s.%s" %
(obj, module, name))
你能試試哪條線路失敗嗎?
當pickle piclkes類和函數如module.function
它會重新確認這是正確的函數意味着:
# module.py
def function(): # 1
pass
a = function
def function(): # 2
pass
在功能1 a
不能被酸洗,但因為它的下模塊中發現的功能2可以腌__name__
它具有為“功能”。
因此,在您的情況下,pickle在reduce
模塊中找不到與作為參數傳遞的相同的類Foo
。 Foo
聲稱可以在模塊reduce
找到。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.