【问题标题】:Pickle and exec in pythonpython中的pickle和exec
【发布时间】:2015-07-02 18:24:29
【问题描述】:

¡大家好!

我要做的是:

import pickle

exec "def f():    print 'Hi!'"
code = pickle.dumps(f)

print code

如您所见,它运行良好。

但是,为了避免定义全局变量,(例如前面代码中的 f),我想做这样的事情:

import pickle

d = {}
exec "def f():    print 'Hi!'" in d
d['f']()

code = pickle.dumps(d['f'])
print code

打印'Hi!',表示python将d['f']识别为函数,但不能pickle。

您知道如何执行此操作吗? 我认为这是因为在前一种情况下,python 知道在哪里可以找到函数(它在 '__main__' 中),但在后一种情况下,它位于位于 '__main__' 的字典中,我认为如果你能告诉 python这个函数的真正模块方向,它会起作用。

谢谢!

【问题讨论】:

  • "为了避免定义全局变量..." 如果您甚至对在全局范围内定义函数犹豫不决,您可能也会接受这个建议远的。无论如何,d 是全球性的,所以你在这里并没有真正获得太多。
  • 我的意思是我不喜欢在使用命令exec()的时候,它定义了全局变量(比如我在程序中没有定义f,它是在后面定义的)使用执行)。这就是为什么我必须将所有这些变量保存在一个字典中。这是通过在dict中使用exec代码来完成的
  • 我建议不要使用exec。只需定期写您的def f():
  • 但实际上,字符串会被任何python代码替换,我不知道它是什么,这就是为什么我需要使用exec。

标签: python exec eval pickle


【解决方案1】:

pickle 按名称腌制函数。它没有尝试转储和恢复字节码,而是说“好的,这个函数是__main__.f,所以要取消它,查看__main__ 模块并检索名为f 的东西”。这是非常必要的;如果您在 f 不存在或执行不同操作的解释器环境中 unpickle 函数 f,那么为了保留 unpickled 函数的原始行为,您需要以某种方式保留它引用的所有函数,所有它使用的模块、所有不再存在的全局变量等。您需要确保在 f 中对 f 的递归引用使用 unpickled 函数而不是新解释器的 f,一切都变得一团糟。

这一切的重点是腌制函数必须是全局的。如果你在他们__module__指定的模块中查找他们__name__命名的东西,你必须找到这个函数,否则你不能解压它。因此,您不能exec 伪造全局字典中的函数定义,并且执行您想要腌制的函数的定义是一个非常容易出错的操作。

【讨论】:

    【解决方案2】:

    我在这里找到了一个非常好的解决方案: Dynamically importing Python module

    解决上述问题的代码是这样的:

    import pickle
    import sys
    import imp
    
    foo = imp.new_module("foo")
    sys.modules["foo"] = foo
    
    exec "def f():    print 'Hi!'" in foo.__dict__
    
    code = pickle.dumps(foo.f)
    print code
    

    如您所见,解决方案是构建一个新模块,该功能将是可腌制的

    【讨论】:

      猜你喜欢
      • 2014-08-07
      • 2015-03-20
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-11-25
      相关资源
      最近更新 更多