本文介绍了在腌制一个类时,我在python中得到了不同的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下文件层次结构:

  python / apps / A.py 
/ geometrylib / __ init__。 py
/geometrylib/B.py
/geometrylib/geometry.py
/geometrylib/goemetry.pyx
/geometrylib/goemetry.pyd

geometry.pyx和geometry.py包含相同的类Camera(cython版本使用cdef定义类)。 A.py和B.py都导入几何模块。



如果我导入cython版本(编译为geometry.pyd),我可以正确地从B内腌制相机python / geometrylib文件夹中的.py。但是我不能在python / apps文件夹中从A.py中腌制Camera,我得到以下异常:



pickle.PicklingError:不能pickle:它不是找到geometry.Camera



但是,如果我删除了geometry.pyd而我导入python版本(geometry.py),那么我可以从A中腌制相机.py或B.py.除了删除geometry.pyd之外别无其他任何变化,同样的python命令行,在两种情况下都从同一文件夹运行。
为什么会出现这种差异?



挖掘一下我发现C:\Python27 \Lib \中发生异常pickle.py第742行

 尝试:
__import __(模块)#line 742
mod = sys。 modules [module]
klass = getattr(mod,name)
除(ImportError,KeyError,AttributeError):
raise PicklingError(
不能pickle%r:它不是找到%s。%s%
(obj,模块,名称))

在A.py中我导入cython版本(geometry.pyd),(我挑选一个Camera实例来触发预期)模块是几何和 __ import __(模块)触发异常。在A.py中我导入python版本(geometry.py),(我挑选一个Camera实例来触发预期)模块是geometrylib.geometry和 __ import __(模块)正确导入模块。



我已经通过将python / geometrylib添加到PYTHONPATH解决了这个问题,然后我可以使用cython版本从A.py和B.py中正确地腌制相机。



这是怎么回事?我不喜欢我的解决方案。 是否有人有更好的解决方案?



编辑以添加一些额外信息。



另外,根据请求,这是我用来构建cython扩展的setup.py。

 来自distutils.core导入设置来自distutils.extension的
导入扩展
来自Cython.Distutils import build_ext
import numpy

setup(
cmdclass = {'build_ext':build_ext},
ext_modules = [Extension(geometry,['geometry.pyx'],include_dirs = [numpy.get_include(),。])])


解决方案

您正在构建geometry.pyx作为顶级模块,而实际上它是<$ c $的一部分c> geometrylib 包。因此, Camera 类被分配了错误的 __ module __ 值( geometry 而不是 geometrylib.geometry )和pickler在尝试查找名为 geometry 的顶级模块时失败。 / p>

您应该遵循标准的包装指南,即将setup.py放入顶级模块(geometrylib)旁边的Python文件夹中。安装调用将如下所示:

  setup(
cmdclass = {'build_ext':build_ext},
ext_modules = [Extension(geometrylib.geometry,['geometrylib / geometry.pyx'],include_dirs = [numpy.get_include(),。])])


I have the following file hierarchy:

python/apps/A.py
      /geometrylib/__init__.py
      /geometrylib/B.py
      /geometrylib/geometry.py
      /geometrylib/goemetry.pyx
      /geometrylib/goemetry.pyd

geometry.pyx and geometry.py contain the same class Camera (the cython version defines the class with cdef ). Both A.py and B.py import the geometry module.

If I import the cython version(compiled to geometry.pyd), I can correctly pickle Camera from within B.py in the python/geometrylib folder. But I can't pickle Camera from A.py in the python/apps folder, I get the following exception:

pickle.PicklingError: Can't pickle : it's not found as geometry.Camera

However, if I delete the geometry.pyd and I import the python version(geometry.py) instead, then I can pickle Camera from either A.py or B.py. Nothing else changes apart from deleting geometry.pyd, same python command line, run from the same folder in both cases.why this difference?

Digging a bit I see that the exception occurs in C:\Python27\Lib\pickle.py line 742

try:
    __import__(module)            #line 742
    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))

When in A.py I import the cython version(geometry.pyd), (and I pickle a Camera instance to trigger the expection) module is "geometry" and __import__(module) triggers the exception. When in A.py I import the python version(geometry.py),(and I pickle a Camera instance to trigger the expection) module is "geometrylib.geometry" and __import__(module) imports the module correctly.

I have solved the problem by adding python/geometrylib to PYTHONPATH, then I can correctly pickle Camera from both A.py and B.py using the cython version.

Is this how is it supposed to work? I don't like my solution. Does anybody have a better solution?

EDITED to add some extra information.

Also, by request, this is the setup.py I used to build the cython extension.

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

setup(
    cmdclass = { 'build_ext': build_ext},
    ext_modules = [Extension("geometry", ['geometry.pyx'], include_dirs=[numpy.get_include(), "."])])
解决方案

You are building geometry.pyx as a top-level module, while in fact it is part of geometrylib package. As a result, Camera class gets assigned incorrect __module__ value (geometry instead of geometrylib.geometry) and pickler fails when it tries to find top-level module named geometry.

You should follow standard packaging guidelines, i.e. put setup.py into "Python" folder, next to the top-level module (geometrylib). setup call will look like this:

setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = [Extension("geometrylib.geometry", ['geometrylib/geometry.pyx'], include_dirs=[numpy.get_include(), "."])])

这篇关于在腌制一个类时,我在python中得到了不同的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-20 15:05