【问题标题】:Does the dill python module handle importing modules when sys.path differs?当 sys.path 不同时, dill python 模块是否处理导入模块?
【发布时间】:2015-10-31 07:21:12
【问题描述】:

我正在评估莳萝,我想知道这种情况是否得到处理。我有一个案例,我在 python 进程中成功导入了一个模块。我可以使用 dill 进行序列化,然后将该模块加载到具有不同 sys.path 且不包含该模块的不同进程中吗?现在我遇到导入失败,但也许我做错了什么。

这是一个例子。我在 foo.py 模块的路径在我的 sys.path 中运行此脚本:

% cat dill_dump.py 
import dill
import foo
myFile = "./foo.pkl"
fh = open(myFile, 'wb')
dill.dump(foo, fh)

现在,我在我的 PYTHONPATH 中没有 foo.py 目录的地方运行这个脚本:

% cat dill_load.py 
import dill
myFile = "./foo.pkl"
fh = open(myFile, 'rb')
foo = dill.load(fh)
print foo

此堆栈跟踪失败:

Traceback (most recent call last):
  File "dill_load.py", line 4, in <module>
    foo = dill.load(fh)
  File "/home/b/lib/python/dill-0.2.4-py2.6.egg/dill/dill.py", line 199, in load
    obj = pik.load()
  File "/rel/lang/python/2.6.4-8/lib/python2.6/pickle.py", line 858, in load
    dispatch[key](self)
  File "/rel/lang/python/2.6.4-8/lib/python2.6/pickle.py", line 1133, in load_reduce
    value = func(*args)
  File "/home/b/lib/python/dill-0.2.4-py2.6.egg/dill/dill.py", line 678, in _import_module
    return __import__(import_name)
ImportError: No module named foo

那么,如果我需要在两个进程之间有相同的 python 路径,那么序列化 python 模块有什么意义呢?或者换句话说,通过 dill 加载 foo 比仅仅调用“import foo”有什么优势吗?

【问题讨论】:

    标签: python dill pathos


    【解决方案1】:

    这是一个有趣的失败。请注意,如果您执行dill.dumps(foo),您将获得模块foo 的内容......失败的部分是使用python 的内置导入钩子(__import__)来做的只是将模块注册到sys.modules .应该可以解决这个问题并修改dill,以便在 PYTHONPATH 中找不到该模块时可以导入该模块。但是,我确实认为必须在 PYTHONPATH 中找到模块是正确的……这是对模块的期望……所以我不确定这是否是个好主意。但也有可能……

    如上所述,对于文件foo.py,其内容为:hello = "hello world, I am foo"

    >>> import dill
    >>> import foo
    >>> dill.dumps(foo)
    '\x80\x02cdill.dill\n_import_module\nq\x00U\x03fooq\x01\x85q\x02Rq\x03}q\x04(U\x08__name__q\x05h\x01U\x08__file__q\x06U\x06foo.pyq\x07U\x05helloq\x08U\x15hello world, I am fooq\tU\x07__doc__q\nNU\x0b__package__q\x0bNub.'
    

    可以看到文件内容保存在pickle中。

    dill 与模块一起使用的主要原因是dill 可以记录对模块的动态修改。例如,添加一个函数或其他对象:

    >>> import foo 
    >>> import dill
    >>> foo.a = 100
    >>> with open('foo.pkl', 'w') as f:
    ...   dill.dump(foo, f)
    ... 
    >>> 
    

    然后重新启动...(在 PYTHONPATH 中使用 foo

    Python 2.7.10 (default, May 25 2015, 13:16:30) 
    [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
    >>> with open('foo.pkl', 'r') as f:
    ...   foo = dill.load(f)
    ... 
    >>> foo.hello
    'hello world, I am foo'
    >>> foo.a
    100
    >>> 
    

    我已将此作为错误报告/功能请求添加:https://github.com/uqfoundation/dill/issues/123

    【讨论】:

    • 关于如何实现这一点的一个建议是在序列化数据流中捕获 sys.path,以便您知道加载时 foo 模块的帧在哪里。这将很有用,因为它将允许 python 状态的更大可移植性,您可以在具有不同设置的机器或 shell 上加载 python 会话。
    • @BrentV:好主意。该信息实际上应该在__file__ 属性中。所以foo.__file__ 会告诉你它是从哪里加载的。当然,这只能在同一台计算机上使用,因此它不是一个完全便携的解决方案。我打算使用inspectdill.source.getsource 捕获整个模块代码。
    猜你喜欢
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-09
    相关资源
    最近更新 更多