2

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関数が新しい値を返して出力するように、値を検査するか、場合によっては変更したいと思います。

最初に nine.py を起動し、次にinspect_shellを使用して別のコマンド ウィンドウで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)]
4

2 に答える 2

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を使用する必要があります。

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')

simple exec(にある場合は'number_nine'を置き換えますglobals)または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!

于 2012-01-04T20:25:39.720 に答える
1

Inspect Shell の作成者はこちら :) おそらく x をグローバル名前空間からアクセスできるようにする必要があるでしょう。Inspect Shell は基本的に、実行中のスクリプトのグローバル名前空間にユーザーをドロップするため、そこからアクセスできないデータがある場合、アクセスするのは非常に困難になります。

したがって、実際の提案は、x をグローバルにすることです。そうすれば、それを変更できるはずであり、number_nine() 関数が返されます。

それが役立つことを願っています!

于 2012-02-03T07:28:25.930 に答える