`pickle`: yet another `ImportError: No module named my_module`
`pickle`: yet another `ImportError: No module named my_module`
我在 my_module
中定义了一个 class MyClass
。 MyClass
有一个方法 pickle_myself
可以 pickle 有问题的 class 的实例:
def pickle_myself(self, pkl_file_path):
with open(pkl_file_path, 'w+') as f:
pkl.dump(self, f, protocol=2)
我已经确定 my_module
在 PYTHONPATH
中。在解释器中,执行 __import__('my_module')
工作正常:
>>> __import__('my_module')
<module 'my_module' from 'A:\my_stuff\my_module.pyc'>
然而,当最终加载文件时,我得到:
File "A:\Anaconda\lib\pickle.py", line 1128, in find_class
__import__(module)
ImportError: No module named my_module
我确定的一些事情:
我没有更改my_module.py
的位置(Python pickling after changing a module's directory)
我试过用dill
代替,但还是报同样的错误(More on python ImportError No module named)
编辑——重现错误的玩具示例:
示例本身分布在一堆文件中。
首先,我们有模块 ball
(存储在名为 ball.py
的文件中):
class Ball():
def __init__(self, ball_radius):
self.ball_radius = ball_radius
def say_hello(self):
print "Hi, I'm a ball with radius {}!".format(self.ball_radius)
然后,我们有模块 test_environment
:
import os
import ball
#import dill as pkl
import pickle as pkl
class Environment():
def __init__(self, store_dir, num_balls, default_ball_radius):
self.store_dir = store_dir
self.balls_in_environment = [ball.Ball(default_ball_radius) for x in range(num_balls)]
def persist(self):
pkl_file_path = os.path.join(self.store_dir, "test_stored_env.pkl")
with open(pkl_file_path, 'w+') as f:
pkl.dump(self, f, protocol=2)
然后,我们有一个模块,它具有创建环境、持久化和加载它们的功能,称为 make_persist_load
:
import os
import test_environment
#import pickle as pkl
import dill as pkl
def make_env_and_persist():
cwd = os.getcwd()
my_env = test_environment.Environment(cwd, 5, 5)
my_env.persist()
def load_env(store_path):
stored_env = None
with open(store_path, 'rb') as pkl_f:
stored_env = pkl.load(pkl_f)
return stored_env
然后我们有一个脚本将它们放在一起,在 test_serialization.py
:
import os
import make_persist_load
MAKE_AND_PERSIST = True
LOAD = (not MAKE_AND_PERSIST)
cwd = os.getcwd()
store_path = os.path.join(cwd, "test_stored_env.pkl")
if MAKE_AND_PERSIST == True:
make_persist_load.make_env_and_persist()
if LOAD == True:
loaded_env = make_persist_load.load_env(store_path)
为了方便使用这个玩具示例,I have put it all up on in a Github repository that simply needs to be cloned into your directory of choice.。请参阅包含说明的 README
,我也将其复制在这里:
说明:
1) 将存储库克隆到目录中。
2) 将存储库目录添加到 PYTHONPATH。
3) 打开test_serialization.py
,设置变量MAKE_AND_PERSIST
为True
。 运行 解释器中的脚本。
4) 关闭之前的解释器实例,并启动一个新的。在 test_serialization.py
中,将 MAKE_AND_PERSIST
更改为 False
,这将以编程方式将 LOAD
设置为 True
。 运行 解释器中的脚本,导致 ImportError: No module named test_environment
。
5) 默认情况下,测试设置为使用 dill,而不是 pickle。要更改此设置,请进入 test_environment.py
和 make_persist_load.py
,根据需要更改导入。
编辑:切换到 dill '0.2.5.dev0' 后,dill.detect.trace(True)
输出
C2: test_environment.Environment
# C2
D2: <dict object at 0x000000000A9BDAE8>
C2: ball.Ball
# C2
D2: <dict object at 0x000000000AA25048>
# D2
D2: <dict object at 0x000000000AA25268>
# D2
D2: <dict object at 0x000000000A9BD598>
# D2
D2: <dict object at 0x000000000A9BD9D8>
# D2
D2: <dict object at 0x000000000A9B0BF8>
# D2
# D2
编辑: 当 运行 在 Mac/Ubuntu 上(即类 Unix 系统?)时,玩具示例工作得非常好。它仅在 Windows 上失败。
我可以从你的问题中看出你可能正在做这样的事情,使用 class 方法试图 pickle class 的实例。这样做是不明智的,如果你这样做的话......在 class 外部使用 pkl.dump
更明智(其中 pkl
是 pickle
或 dill
等)。然而,它可以仍然适用于这种设计,见下文:
>>> class Thing(object):
... def pickle_myself(self, pkl_file_path):
... with open(pkl_file_path, 'w+') as f:
... pkl.dump(self, f, protocol=2)
...
>>> import dill as pkl
>>>
>>> t = Thing()
>>> t.pickle_myself('foo.pkl')
然后重新启动...
Python 2.7.10 (default, Sep 2 2015, 17:36:25)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> f = open('foo.pkl', 'r')
>>> t = dill.load(f)
>>> t
<__main__.Thing object at 0x1060ff410>
如果你有一个更复杂的 class,我相信你有,那么你可能 运行 会遇到麻烦,尤其是如果那个 class 使用了另一个文件位于同一目录中。
>>> import dill
>>> from bar import Zap
>>> print dill.source.getsource(Zap)
class Zap(object):
x = 1
def __init__(self, y):
self.y = y
>>>
>>> class Thing2(Zap):
... def pickle_myself(self, pkl_file_path):
... with open(pkl_file_path, 'w+') as f:
... dill.dump(self, f, protocol=2)
...
>>> t = Thing2(2)
>>> t.pickle_myself('foo2.pkl')
然后重新启动...
Python 2.7.10 (default, Sep 2 2015, 17:36:25)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> f = open('foo2.pkl', 'r')
>>> t = dill.load(f)
>>> t
<__main__.Thing2 object at 0x10eca8090>
>>> t.y
2
>>>
好吧……拍,这也行。你必须 post 你的代码,这样我们才能看到你使用的是什么模式 dill
(和 pickle
)失败了。我知道让一个模块导入另一个不是 "installed" 的模块(即在某个本地目录中)并且期望序列化为 "just work" 并不适用于所有情况。
参见 dill
个问题:
https://github.com/uqfoundation/dill/issues/128
https://github.com/uqfoundation/dill/issues/129
这个问题:
一些失败的例子和潜在的解决方法。
EDIT 关于更新的问题:
我没有看到你的问题。 运行 从命令行,从解释器导入 (import test_serialization
),并在解释器中 运行ning 脚本(如下所示,并在步骤 3-5 中指出)都可以。这使我认为您可能正在使用旧版本的 dill
?
>>> import os
>>> import make_persist_load
>>>
>>> MAKE_AND_PERSIST = False #True
>>> LOAD = (not MAKE_AND_PERSIST)
>>>
>>> cwd = os.getcwd()
>>> store_path = os.path.join(cwd, "test_stored_env.pkl")
>>>
>>> if MAKE_AND_PERSIST == True:
... make_persist_load.make_env_and_persist()
...
>>> if LOAD == True:
... loaded_env = make_persist_load.load_env(store_path)
...
>>>
编辑 根据评论中的讨论:
看起来这可能是 Windows 的问题,因为这似乎是唯一 OS 出现的错误。
编辑 经过一些工作(参见:https://github.com/uqfoundation/dill/issues/140):
使用这个最小的示例,我可以在 Windows 上重现相同的错误,而在 MacOSX 上它仍然有效......
# test.py
class Environment():
def __init__(self):
pass
和
# doit.py
import test
import dill
env = test.Environment()
path = "test.pkl"
with open(path, 'w+') as f:
dill.dump(env, f)
with open(path, 'rb') as _f:
_env = dill.load(_f)
print _env
但是,如果您使用 open(path, 'r') as _f
,它可以在 Windows 和 MacOSX 上使用。所以看起来 Windows 上的 __import__
比非 Windows 系统对文件类型更敏感。尽管如此,抛出一个 ImportError
还是很奇怪……但是这个小小的改变应该可以让它起作用。
万一有人遇到同样的问题,我遇到了同样的问题 运行 Python 2.7,问题是在 windows 创建的 pickle 文件,而我 运行 Linux,我要做的是 运行 dos2unix 必须先使用
下载
sudo yum install dos2unix
然后你需要转换 pickle 文件示例
dos2unix data.p
我在 my_module
中定义了一个 class MyClass
。 MyClass
有一个方法 pickle_myself
可以 pickle 有问题的 class 的实例:
def pickle_myself(self, pkl_file_path):
with open(pkl_file_path, 'w+') as f:
pkl.dump(self, f, protocol=2)
我已经确定 my_module
在 PYTHONPATH
中。在解释器中,执行 __import__('my_module')
工作正常:
>>> __import__('my_module')
<module 'my_module' from 'A:\my_stuff\my_module.pyc'>
然而,当最终加载文件时,我得到:
File "A:\Anaconda\lib\pickle.py", line 1128, in find_class
__import__(module)
ImportError: No module named my_module
我确定的一些事情:
我没有更改
my_module.py
的位置(Python pickling after changing a module's directory)我试过用
dill
代替,但还是报同样的错误(More on python ImportError No module named)
编辑——重现错误的玩具示例:
示例本身分布在一堆文件中。
首先,我们有模块 ball
(存储在名为 ball.py
的文件中):
class Ball():
def __init__(self, ball_radius):
self.ball_radius = ball_radius
def say_hello(self):
print "Hi, I'm a ball with radius {}!".format(self.ball_radius)
然后,我们有模块 test_environment
:
import os
import ball
#import dill as pkl
import pickle as pkl
class Environment():
def __init__(self, store_dir, num_balls, default_ball_radius):
self.store_dir = store_dir
self.balls_in_environment = [ball.Ball(default_ball_radius) for x in range(num_balls)]
def persist(self):
pkl_file_path = os.path.join(self.store_dir, "test_stored_env.pkl")
with open(pkl_file_path, 'w+') as f:
pkl.dump(self, f, protocol=2)
然后,我们有一个模块,它具有创建环境、持久化和加载它们的功能,称为 make_persist_load
:
import os
import test_environment
#import pickle as pkl
import dill as pkl
def make_env_and_persist():
cwd = os.getcwd()
my_env = test_environment.Environment(cwd, 5, 5)
my_env.persist()
def load_env(store_path):
stored_env = None
with open(store_path, 'rb') as pkl_f:
stored_env = pkl.load(pkl_f)
return stored_env
然后我们有一个脚本将它们放在一起,在 test_serialization.py
:
import os
import make_persist_load
MAKE_AND_PERSIST = True
LOAD = (not MAKE_AND_PERSIST)
cwd = os.getcwd()
store_path = os.path.join(cwd, "test_stored_env.pkl")
if MAKE_AND_PERSIST == True:
make_persist_load.make_env_and_persist()
if LOAD == True:
loaded_env = make_persist_load.load_env(store_path)
为了方便使用这个玩具示例,I have put it all up on in a Github repository that simply needs to be cloned into your directory of choice.。请参阅包含说明的 README
,我也将其复制在这里:
说明:
1) 将存储库克隆到目录中。
2) 将存储库目录添加到 PYTHONPATH。
3) 打开test_serialization.py
,设置变量MAKE_AND_PERSIST
为True
。 运行 解释器中的脚本。
4) 关闭之前的解释器实例,并启动一个新的。在 test_serialization.py
中,将 MAKE_AND_PERSIST
更改为 False
,这将以编程方式将 LOAD
设置为 True
。 运行 解释器中的脚本,导致 ImportError: No module named test_environment
。
5) 默认情况下,测试设置为使用 dill,而不是 pickle。要更改此设置,请进入 test_environment.py
和 make_persist_load.py
,根据需要更改导入。
编辑:切换到 dill '0.2.5.dev0' 后,dill.detect.trace(True)
输出
C2: test_environment.Environment
# C2
D2: <dict object at 0x000000000A9BDAE8>
C2: ball.Ball
# C2
D2: <dict object at 0x000000000AA25048>
# D2
D2: <dict object at 0x000000000AA25268>
# D2
D2: <dict object at 0x000000000A9BD598>
# D2
D2: <dict object at 0x000000000A9BD9D8>
# D2
D2: <dict object at 0x000000000A9B0BF8>
# D2
# D2
编辑: 当 运行 在 Mac/Ubuntu 上(即类 Unix 系统?)时,玩具示例工作得非常好。它仅在 Windows 上失败。
我可以从你的问题中看出你可能正在做这样的事情,使用 class 方法试图 pickle class 的实例。这样做是不明智的,如果你这样做的话......在 class 外部使用 pkl.dump
更明智(其中 pkl
是 pickle
或 dill
等)。然而,它可以仍然适用于这种设计,见下文:
>>> class Thing(object):
... def pickle_myself(self, pkl_file_path):
... with open(pkl_file_path, 'w+') as f:
... pkl.dump(self, f, protocol=2)
...
>>> import dill as pkl
>>>
>>> t = Thing()
>>> t.pickle_myself('foo.pkl')
然后重新启动...
Python 2.7.10 (default, Sep 2 2015, 17:36:25)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> f = open('foo.pkl', 'r')
>>> t = dill.load(f)
>>> t
<__main__.Thing object at 0x1060ff410>
如果你有一个更复杂的 class,我相信你有,那么你可能 运行 会遇到麻烦,尤其是如果那个 class 使用了另一个文件位于同一目录中。
>>> import dill
>>> from bar import Zap
>>> print dill.source.getsource(Zap)
class Zap(object):
x = 1
def __init__(self, y):
self.y = y
>>>
>>> class Thing2(Zap):
... def pickle_myself(self, pkl_file_path):
... with open(pkl_file_path, 'w+') as f:
... dill.dump(self, f, protocol=2)
...
>>> t = Thing2(2)
>>> t.pickle_myself('foo2.pkl')
然后重新启动...
Python 2.7.10 (default, Sep 2 2015, 17:36:25)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> f = open('foo2.pkl', 'r')
>>> t = dill.load(f)
>>> t
<__main__.Thing2 object at 0x10eca8090>
>>> t.y
2
>>>
好吧……拍,这也行。你必须 post 你的代码,这样我们才能看到你使用的是什么模式 dill
(和 pickle
)失败了。我知道让一个模块导入另一个不是 "installed" 的模块(即在某个本地目录中)并且期望序列化为 "just work" 并不适用于所有情况。
参见 dill
个问题:
https://github.com/uqfoundation/dill/issues/128
https://github.com/uqfoundation/dill/issues/129
这个问题:
EDIT 关于更新的问题:
我没有看到你的问题。 运行 从命令行,从解释器导入 (import test_serialization
),并在解释器中 运行ning 脚本(如下所示,并在步骤 3-5 中指出)都可以。这使我认为您可能正在使用旧版本的 dill
?
>>> import os
>>> import make_persist_load
>>>
>>> MAKE_AND_PERSIST = False #True
>>> LOAD = (not MAKE_AND_PERSIST)
>>>
>>> cwd = os.getcwd()
>>> store_path = os.path.join(cwd, "test_stored_env.pkl")
>>>
>>> if MAKE_AND_PERSIST == True:
... make_persist_load.make_env_and_persist()
...
>>> if LOAD == True:
... loaded_env = make_persist_load.load_env(store_path)
...
>>>
编辑 根据评论中的讨论:
看起来这可能是 Windows 的问题,因为这似乎是唯一 OS 出现的错误。
编辑 经过一些工作(参见:https://github.com/uqfoundation/dill/issues/140):
使用这个最小的示例,我可以在 Windows 上重现相同的错误,而在 MacOSX 上它仍然有效......
# test.py
class Environment():
def __init__(self):
pass
和
# doit.py
import test
import dill
env = test.Environment()
path = "test.pkl"
with open(path, 'w+') as f:
dill.dump(env, f)
with open(path, 'rb') as _f:
_env = dill.load(_f)
print _env
但是,如果您使用 open(path, 'r') as _f
,它可以在 Windows 和 MacOSX 上使用。所以看起来 Windows 上的 __import__
比非 Windows 系统对文件类型更敏感。尽管如此,抛出一个 ImportError
还是很奇怪……但是这个小小的改变应该可以让它起作用。
万一有人遇到同样的问题,我遇到了同样的问题 运行 Python 2.7,问题是在 windows 创建的 pickle 文件,而我 运行 Linux,我要做的是 运行 dos2unix 必须先使用
下载sudo yum install dos2unix
然后你需要转换 pickle 文件示例
dos2unix data.p