簡體   English   中英

包中的Cython Pickling“未找到”錯誤

[英]Cython Pickling in Package “not found as” Error

我在挑選一個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,)

設置文件

這可以使用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酸洗

但是,一旦將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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM