我无法弄清楚如何使用inspect / inspect_shell来检查当前正在执行的函数
我猜它涉及使用getinnerframe和getouterframe遍历帧层次结构,但我对几个问题感到困惑。
给出这个例子 nine.py:
import inspect_shell
import time
def number_nine():
x = 9
while x==9:
time.sleep(1)
number_nine()
print x
我想检查x
的值,或者甚至可能更改它以使函数返回并打印新值。
首先我使用inspect_shell启动nine.py,然后在单独的命令窗口中,我看到getinnerframes
在当前帧上不起作用(它需要跟踪(可能是?))和当前帧没有“跟踪”。和getouterframes
(如果我正在考虑这个问题)似乎只得到与我的功能无关的帧。
>> Inspect Shell v1.0
>> https://github.com/amoffat/Inspect-Shell
localhost:1234> import inspect
localhost:1234> f = inspect.currentframe()
localhost:1234> inspect.getinnerframes(f)
Traceback (most recent call last):
File "C:\Users\Paul\Desktop\inspect_shell.py", line 143, in run_repl
try: exec compile(data, "<dummy>", "single") in f_globals, f_globals
File "<dummy>", line 1, in <module>
File "C:\Python26\lib\inspect.py", line 942, in getinnerframes
framelist.append((tb.tb_frame,) + getframeinfo(tb, context))
AttributeError: 'frame' object has no attribute 'tb_frame'
localhost:1234> dir(f)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__',
'__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
'__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'f_back', 'f_builtins',
'f_code', 'f_exc_traceback', 'f_exc_type', 'f_exc_value', 'f_glo
bals', 'f_lasti', 'f_lineno', 'f_locals', 'f_restricted', 'f_trace']
localhost:1234> print f.f_trace
None
localhost:1234> inspect.getouterframes(f)
[(<frame object at 0x0237D470>, '<dummy>', 1, '<module>', None, None),
(<frame object at 0x02375938>, 'C:\\Users\\Paul\\Desktop\\inspect_shell.py', 14
3, 'run_repl', [' try: exec compile(data, "<dummy>", "single") in
f_globals, f_globals\n'], 0), (<frame object at 0x023A2C30>, 'C:\
\Python26\\lib\\threading.py', 484, 'run',
[' self.__target(*self.__args, **self.__kwargs)\n'], 0),
(<frame object at 0x02397F28>, 'C:\
\Python26\\lib\\threading.py', 532, '__bootstrap_inner',
[' self.run()\n'], 0), (<frame object at 0x023A9D68>,
'C:\\Python26\\lib\\thre
ading.py', 504, '__bootstrap', [' self.__bootstrap_inner()\n'], 0)]
答案 0 :(得分:3)
这有点棘手,但鉴于源代码(或一个好的python反编译器),你可以这样做:
在'nine.py'中:
def number_nine():
x = 9
if x == 9:
print 'x is Nine!'
else:
print 'x:', x
你的邪恶代码:
from nine import number_nine
我们需要使用ast,Abstract Syntax Trees:
import inspect
import ast
现在我们获取源并将其转换为ast:
# Assuming you have the source, we can generate AST from it
nine_src = inspect.getsource(number_nine)
nine_ast = ast.parse(nine_src)
隔离您要更改的特定声明:
# This is the Assign object, which represents the 'x = 9' line
# Try to run it interactivly and see how it looks...
x_assign = nine_ast.body[0].body[0]
# Prints 'x'
print x_assign.targets[0].id
# Prints 9
print x_assign.value.n
根据你的意愿改变它:
# Change the value of x
# Notice, that we change the assignment itself, a.k.a `x = 9` is now `x = "It's a trap!"`
x_assign.value.n = "It's a trap!"
现在剩下要做的就是将修改后的ast对象编译成更有用的东西:
# Compile the new function
new_nine = compile(nine_ast, 'new_nine', 'exec')
您可以使用简单的exec
(如果它位于globals
中,则会替换'number_nine')或exec in
,并将其放在临时模块中:
# Now we need to execute our litle new_nine (which is a code object)
# This to create the modified version in 'm'
import types
m = types.ModuleType('m', 'The m module')
exec new_nine in m.__dict__
m.number_nine()
# Or this to create it in the global scope
exec new_nine
number_nine()
砰!它会打印x: It's a trap!
答案 1 :(得分:1)
Inspect Shell的作者:)你可能需要从全局命名空间访问x。 Inspect Shell基本上将你放入正在运行的脚本的全局命名空间中,因此如果从那里无法访问某些数据,那么实现它将非常棘手。
所以真正的建议是,make x global,然后你应该能够改变它,你的number_nine()函数将会返回。
希望有所帮助!