丢失了重要的 .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
$
虽然管理多个不同的屏幕会话并在其中许多会话中打开 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
$