丢失了重要的 .py 文件(被覆盖为 0byte 文件),但旧版本仍作为模块加载到 IPYTHON 中——可以找回吗?

Lost important .py file (overwritten as 0byte file), but the old version still LOADED IN IPYTHON as module -- can it be retrieved?

虽然管理多个不同的屏幕会话并在其中许多会话中打开 vim,但在尝试“组织”我的会话的过程中,我以某种方式设法用 0Byte 文件覆盖了一个非常重要的 .py 脚本。

但是,我打开了一个 ipython 实例,当 运行 与模块相同的 .py 文件时,仍然记得曾经存在的代码!

我是不是刚刚学到了关于备份的惨痛教训(我的上一次备份是 vim 大约一周前完成的,这会让我有很多工作要做),或者有没有可能,从已加载的模块中检索 .py 文件的可能方法?我可能因如此傲慢而活该,但我真的很绝望。

您应该可以使用 inspect

在您的 Ipython 会话中导入 inspect,假设您正在尝试恢复 myModule,请执行:

q = inspect.getsource(myModule)

并将q写入文件。

[编辑] 这对我有用 Python 2.7.6, IPython 1.2.1

来模拟问题

[编辑#2]

如评论中所述,inspect.getsource 将不起作用,因为它取决于原始文件(即 module.__file__)。

最佳选择:检查是否有 .pyc 文件(例如,foo.pyc 应该在 foo.py 旁边)。如果有,可以用Decompile Python 2.7 .pyc反编译。

inspect 模块也缓存源代码。您可能会幸运地使用 inspect.getsource(module),或者 inspect.getsourcelines(module.function)(如果过去曾调用过)。

否则您将需要通过检查导出(即 module.__globals__)来重建模块 "manually"。常量和诸如此类的东西是显而易见的,对于函数,您可以使用 func.func_name 获取其名称,使用 func.__doc__ 获取文档字符串,使用 inspect.getargspec(func) 获取参数,使用 func.func_code 获取有关代码的详细信息: co_firstlineno 将获取行号,然后 co_code 将获取代码。这里有更多关于反编译的内容:Exploring and decompiling python bytecode

例如,要使用 uncompyle2:

>>> def foo():
...     print "Hello, world!"
...
>>> from StringIO import StringIO
>>> import uncompyle2
>>> out = StringIO()
>>> uncompyle2.uncompyle("2.7", foo.func_code, out=out)
>>> print out.getvalue()
print 'Hello, world!'

但是,不 — 我不知道还有什么更直接的方法可以获取模块并取回源代码。

进程仍在 运行,您可以查看您的命名空间以找到要恢复的候选项:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'readline', 'rlcompleter', 'test']

让我们来看看我们为 test 准备的东西:

>>> help(test)

Help on module test:

NAME
    test

FILE
    /Users/tfisher/code/ffi4wd/test.py

FUNCTIONS
    call_cat(cat)

DATA
    cat_name = 'commander sprinkles'

它的输出比查看 test 内部的局部变量更清晰:

>>> dir(test)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'call_cat', 'cat_name', 'json']

使用inspect module,我们可以得到函数的参数说明:

>>> inspect.getargspec(test.call_cat)
ArgSpec(args=['cat'], varargs=None, keywords=None, defaults=None)

或者我们函数中的行:

>>> inspect.getsourcelines(test.call_cat)
(['def call_cat(cat):\n', '    print("Hello %s" % cat)\n'], 5)

与原文相当接近:

import json

cat_name = 'commander sprinkles'

def call_cat(cat):
    print("Hello %s" % cat)

如果文件在导入后被删除并且没有被更新的同名文件替换(getsourcelines 如果可能使用对象缓存),这应该有效:

$ python -V
Python 2.7.10

$ ls | grep test
$