从Python解释器中恢复.pyc文件

4
因为我很蠢,删除了一些Python文件并且没有备份。在执行此操作之前,我打开了Python解释器(即运行python),然后使用了命令import myfile.py
编辑:实际上我使用了命令import myfile,这似乎更糟糕。
是否有任何方法可以从我已经打开的Python解释器会话中恢复.py(或者最好是.py文件,但这似乎不可能)文件?

@abarnert。是的,那就是我的意思。 - tanderson11
你在哪个平台上?细节在Windows和*nix之间有很大的不同。 - abarnert
很遗憾,正如我在另一个答案中所提到的那样,这会产生一个错误。 - tanderson11
@abarnert 我在Linux上(如果有影响的话,是Ubuntu)。 - tanderson11
@tanderson11:好的,在*nix上,如果.py文件已经被加载,即使您不喜欢该文件,它也将可用,但是如果只加载了.pyc,则.py文件可能永远消失。因此,您需要一种方法来转储.pyc。如果我没记错的话,这在最近的Python中并不简单,但是在旧版本中需要大量的hackery,所以...您使用的是哪个版本? - abarnert
显示剩余4条评论
2个回答

4
字节码反编译器uncompyle2可以将Python 2.x的类、方法、函数和代码反编译为源代码(注意:通过重新组装Python字节码到原始代码?)。

这对于函数来说已经足够好了:

from StringIO import StringIO
from uncompyle2 import uncompyle
from inspect import *

def decompile_function(f, indent=''):
    s = StringIO()
    uncompyle(2.7, f.func_code, s)
    return '%sdef %s%s:\n%s    %s' % (
        indent,
        f.func_name,
        inspect.formatargspec(*inspect.getargspec(f)),
        indent,
        ('\n    ' + indent).join(''.join(s.buflist).split('\n')))

不幸的是,因为类已经执行,它将无法恢复它们的结构;您需要逐个反编译方法,并希望这足够:

def decompile_class(c):
    return 'class %s(%s):\n' % (
        c.__name__,
        ','.join(b.__module__ + '.' + b.__name__ for b in c.__bases__)) + \
        '\n'.join(decompile_function(m.im_func, '    ')
                  for n, m in inspect.getmembers(c) if inspect.ismethod(m))

完整解决方案:

def decompile_module(mod):
    return '\n\n'.join(decompile_function(m) if isfunction(m) else
        decompile_class(m) if isclass(m) else
        '# UNKNOWN: ' + repr((n, m))
        for n, m in inspect.getmembers(mod) if inspect.getmodule(m) is mod)

实际上,inspect.getmembers(myfile) 同样适用于获取所有成员。 - abarnert
但这是一个聪明的想法:不要试图恢复编译代码并找出如何将其转储到 .pyc,而是将其转回源代码并将其转储到功能等效的 .py。好的解决方案! - abarnert
在我的电脑上,如果我没有指定文件,这个操作就会失败:uncompyle.uncompyle(2.7, myfile.myfunc.func_code, open('myfile-1.py','w')) 或者 uncompyle.uncompyle(2.7, myfile.myfunc.func_code, sys.stdout) - loopbackbee
@goncalopp:看起来你正在使用uncompyle而不是uncompyle2。据我所知,它们都是同一个项目的分支,因此使用它们应该非常相似...但是如果有人建议你使用其中一个,而你使用另一个并且它不起作用,那么你应该尝试他建议的那个。 - abarnert
@abarnert 我确实尝试了uncompyle2,但它的行为与之前相同。StringIO是一个很好的解决方法。 - loopbackbee
@goncalopp:只是为了确保你给出的信用归属于正确的人,StringIO 的解决方法是 ecatmur 的想法,而不是我的,就像使用 uncompyle2 来获取你可以有用地保存的东西的主要巧妙之处一样。如果我能的话,我会给他更多的赞扬。 :) - abarnert

1

inspect.getsource支持转储模块,因此您可以轻松实现

import inspect
inspect.getsource(myfile)

由于似乎不起作用,你至少应该能够获取反汇编(".pyc")代码。
import dis
dis.dis(myfile)

产生错误:"IOError:源代码不可用。" - tanderson11
如果这个模块是通过“.pyc”文件而不是“.py”文件导入的,且“.py”文件已被删除,则无法正常工作。 - abarnert
@goncalopp 好的,有了这个我可以访问反汇编代码。显然,从这里我可以更快地拼凑出一个可工作的版本。理想情况下,我希望能够从中恢复Python代码,但我想这是一个有损过程。你有什么想法吗? - tanderson11

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接