【问题标题】:Getting source code from dill pickle file (OSError: could not extract source code)从莳萝泡菜文件中获取源代码(OSError:无法提取源代码)
【发布时间】:2021-09-10 10:07:41
【问题描述】:

进一步阅读this post我们如何从pickle文件中获取源代码

我尝试使用getsource(在阅读this post 之后),但只有在同一会话中定义类时才有效,下面是我尝试过的代码

class Foo(object):
def bar(self, x):
 return self.y + x
def __init__(self, y):
 self.y = y
import dill
     
f = Foo(5)
             
with open('foo.pkl', 'wb') as pkl:
  dill.dump(f, pkl)

with open('foo.pkl', 'rb') as pkl:
 b = dill.load(pkl)

print(b)

#sFoo = dill.source.getsource('foo.pkl') ## error
#sFoo = dill.source.getsource(b) ## error
#sFoo = dill.source.getsource(b.bar) ## error

错误详情 使用sFoo = dill.source.getsource(b) 时错误为OSError: could not extract source code

当使用sFoo = dill.source.getsource(b.bar) 时错误为OSError: could not extract source code

【问题讨论】:

  • 这将有助于查看您遇到的错误。您的第一次和第三次尝试似乎是由于以非预期方式使用该功能。 getsource 从对象中提取代码,因此在 foo.pkl 上调用它没有意义。同样,如果你正在转储f.bar,那么在加载之后,b 应该是 f.bar 的副本......所以b.bar 没有意义,应该是属性错误或类似的。
  • 您好迈克,感谢您的评论。我已经更新了我得到的错误。我同意首先不正确使用getsource。现在不是转储f.bar,而是将其更改为f 如果getsource 不是合法方式,还有其他方法可以检索源代码吗?
  • getsource 是完全合法的获取代码的方式。

标签: python dill


【解决方案1】:

here 进一步阅读我从标准 python 控制台而不是使用 jupyter 运行代码,仍然没有得到正确的结果,但这次比之前没有错误要好

dill.source.getsource(b)

我得到的输出如下

'import dill\ndill.loads(b\'\\x80\\x03cdill._dill\\n_create_type\\nq\\x00(cdill._dill\\n_load_type\\nq\\x01X\\x04\\x00\\x00\\x00typeq\\x02\\x85q\\x03Rq\\x04X\\x03\\x00\\x00\\x00Fooq\\x05h\\x01X\\x06\\x00\\x00\\x00objectq\\x06\\x85q\\x07Rq\\x08\\x85q\\t}q\\n(X\\n\\x00\\x00\\x00__module__q\\x0bX\\x08\\x00\\x00\\x00__main__q\\x0cX\\x03\\x00\\x00\\x00barq\\rcdill._dill\\n_create_function\\nq\\x0e(h\\x01X\\x08\\x00\\x00\\x00CodeTypeq\\x0f\\x85q\\x10Rq\\x11(K\\x02K\\x00K\\x02K\\x02KCC\\n|\\x01|\\x00j\\x00\\x17\\x00S\\x00q\\x12N\\x85q\\x13X\\x01\\x00\\x00\\x00yq\\x14\\x85q\\x15X\\x04\\x00\\x00\\x00selfq\\x16X\\x01\\x00\\x00\\x00xq\\x17\\x86q\\x18X\\x07\\x00\\x00\\x00<stdin>q\\x19h\\rK\\x02C\\x02\\x00\\x01q\\x1a))tq\\x1bRq\\x1cc__builtin__\\n__main__\\nh\\rNN}q\\x1dtq\\x1eRq\\x1fh\\x14K\\x01X\\x07\\x00\\x00\\x00__doc__q NX\\r\\x00\\x00\\x00__slotnames__q!]q"utq#Rq$)\\x81q%.\')\n'

note 的进一步建议是使用dill.source.getsource(dill.detect.code(b)),但这会导致错误为TypeError: None is not a module, class, method, function, traceback, frame, or code object

然后当我尝试dill.source.getsource(b.bar) 时,我得到了完美的结果

>>> dill.source.getsource(b.bar)
'  def bar(self, x):\n    return x+self.y       \n'

现在我得到了一些东西

我们可以做的是首先使用下面的代码跟踪pickle文件,这将给出类中所有函数的列表,然后我们可以使用getsource单独检测它们的源代码。

dill.detect.trace(True)
dill.pickles(b)

【讨论】:

  • 你得到了b 所得到的东西,因为它是一个类的实例 --- 因此,有源代码和状态。如果您改为获得b.__class__(或Foo)的云杉,您应该只获得该类的代码。另外,如果你在b.bar 上使用enclosing=True,你至少应该得到一些(如果不是全部)Foo
  • 另外,jupyter 会混淆命名空间,因此每个单元格都在自己的命名空间中,而不是全局命名空间。因此,如果您将所有代码都放在一个单元格中,它应该可以按预期工作。
  • 感谢 Mike,我在使用 b.__class__ 时确实得到了相关输出。 >>> dill.source.getsource(b.__class__) 'class Foo(object):\n def bar(self, x):\n return self.y + x\n def __init__(self, y):\n self.y = y\n'
  • 除此之外,我还注意到在某些情况下 getsource 不会给出正确的输出,尤其是当我们有 dict 时。无论如何,解决方法是使用 pickletools 并将代码提取到文本文件中,然后使用正则表达式提取所需的字典。使用的命令是python -m pickletools /usr/data/dat.pkl > /usr/data/dat.txt,我现在还不清楚情况(因为我不知道 dat.pkl 是如何创建的,我只知道它是使用 dill 创建的)需要与 dat.pkl 文件的创建者核实明白这一点。
  • @MikeMcKerns 在我们使用b.__dict__ 时,进一步扩展您分享的使用b.__class__ 的知识,我确实在pickle 文件中得到了有效的字典。我认为我的目标已经实现,因此不需要所有疯狂的解决方法。谢谢你的帮助。
猜你喜欢
  • 2020-08-12
  • 2011-07-03
  • 2017-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-26
相关资源
最近更新 更多