2009-07-15 14 views
2

フレームオブジェクト(たとえば、sys._getframeによって返される)を指定すると、呼び出し可能なオブジェクトを取得できますか?フレームから呼び出し可能なオブジェクトを取得する

コードの説明:私の問題は、フレームではなく、現在と呼ばれるオブジェクトのうち、オブジェクトを取得している

def foo(): 
    frame = sys._getframe() 
    x = some_magic(frame) 

    # x is foo, now 

注意。

希望は可能です。

乾杯、

MH

EDIT:

私は多少この問題を回避するために管理してきました。それはAndreasとAlexanderの返答に大きく影響されました。時間を投資してくれてありがとう!

def magic(): 
    fr = sys._getframe(1) 
    for o in gc.get_objects(): 
     if inspect.isfunction(o) and o.func_code is fr.f_code: 
      return o 

class Foo(object): 
    def bar(self): 
     return magic() 

x = Foo().bar() 

assert x is Foo.bar.im_func

その後

、私は積極的にグローバル()またはgc.get_objects()とdirをたどることができます()すべてで(__func____code__im_funcfunc_codeを置き換えるpy3kため、2.6.2で動作します)指定された関数オブジェクトで呼び出し可能なものを検索します。

私には少し気分が悪いですが、機能します。

ありがとう、もう一度!

MH

+0

以下の回答から分かるように、それは可能ですが、それは決してお勧めできません。達成したいことは何ですか?他の方法で行うこともできます。 – Blixt

+0

実際に私がやろうとしているのは、プログラム内のすべての関数呼び出しをログに記録することです(後で関数と呼ばれるものを処理します)。これは、bdbモジュールを使ってすべてのスタックフレームをトレースしています。どのようなアイデアにも深く感謝しています! –

+0

プロセスによって、あなたはそれらに電話したい、あるいはあなたが何か他のことをしたいのですか? – Blixt

答えて

1

は、クラスまたは単にグローバル関数の一部である機能を含むすべてのケースをサポートするために、これを行うことのないストレートな方法はありません。私はあなたを得ることができる最も近いがこれです

...あなたは完全なコールスタックを取得し、globals()を通じてダウンあなたの方法を反復処理することができるかもしれないが、それは素晴らしいではないでしょう。

import sys, types 

def magic(): 
    # Get the frame before the current one (i.e. frame of caller) 
    frame = sys._getframe(1) 
    # Default values and closure is lost here (because they belong to the 
    # function object.) 
    return types.FunctionType(frame.f_code, frame.f_globals) 

class MyClass(object): 
    def foo(self, bar='Hello World!'): 
     print bar 
     return magic() 

test = MyClass() 

new_foo = test.foo() 
new_foo(test, 'Good Bye World!') 

あなたは」全く同じコードを実行しますが、新しいコードラッパー(たとえば、FunctionType)になります。

スタックに基づいてアプリケーションの状態を復元できるように思っています...可能な限り元の呼び出しと同じように関数を呼び出すようなものです(クロージャはまだ除外されています。かなり簡単だろうと呼ばれていた機能)を取得し、フレームからクロージャを得ることができる:

import sys, types 

class MyClass(object): 
    def __init__(self, temp): 
     self.temp = temp 

    def foo(self, bar): 
     print self.temp, bar 
     return sys._getframe() 

def test(hello): 
    print hello, 'World!' 
    return sys._getframe() 

def recall(frame): 
    code = frame.f_code 
    fn = types.FunctionType(
     code, frame.f_globals, code.co_name, 
     # This is one BIG assumption that arguments are always last. 
     tuple(frame.f_locals.values()[-code.co_argcount:])) 
    return fn() 


test1 = MyClass('test1') 
frame1 = test1.foo('Hello World!') 

test2 = MyClass('test2') 
frame2 = test2.foo('Good Bye World!') 
frame3 = test2.foo('Sayonara!') 

frame4 = test('HI') 

print '-' 

recall(frame4) 
recall(frame3) 
recall(frame2) 
recall(frame1) 
+0

この解決策は、呼び出し元のオブジェクトがグローバルスコープで定義された関数であるという前提に基づいています。たとえば、オブジェクトメソッドは正しく処理されません。co_nameはこのメソッドの名前のみを返します。 –

+0

私は参照してください。あなたがやっていることを何でもすることをお勧めしているとは言えませんが、私が考えることができる最も近い解決策で自分の答えを更新しました。 – Blixt

1

少し醜いが、ここにある:

frame.f_globals[frame.f_code.co_name] 

全例:

#!/usr/bin/env python 

import sys 

def foo(): 
    frame = sys._getframe() 
    x = frame.f_globals[frame.f_code.co_name] 

    print foo is x 

foo() 

'True'を表示します。

+0

+1: 'frame.f_globals'は' globals() 'よりも正しいと思います。あなたは 'print foo is x'を意味しましたか? – Blixt

+0

Blixtの答えから私のコメントを守る - 呼び出し可能オブジェクトがf_globalsのようなオブジェクトメソッドに存在しない場合はどうする?あなたの答えをありがとう。 –

+0

@Blixtああ、私は 'print foo is x'を意味しました。それを編集しました。 @Mikeはい、グローバルでない場合、これはうまくいかないでしょう。 –

0

本当に答えは、コメントです。私はコメントとして追加したいが、十分な "評判ポイント"がない。

ここでは、このようなことをしたいと思う合理的な(私が思う)ユースケースがあります。

私のアプリはgtkを使い、多くのスレッドを回転させます。これらの両方を同時に実行したことがある人は、メインスレッドの外にあるGUIに触れることはできません。一般的な回避策は、GUIに触れる呼び出し可能ファイルをidle_add()に渡すことです。これは後で実行するメインスレッドで安全です。だから私はの出現のたくさんを持っている:

def threaded_gui_func(self, arg1, arg2): 
    if threading.currentThread().name != 'MainThread': 
     gobject.idle_add(self.threaded_gui_func, arg1, arg2) 
     return 
    # code that touches the GUI 

私はちょうど

def thread_gui_func(self, arg1, arg2): 
    if idleIfNotMain(): return 
    # code that touches the GUI 

を行うことができれば(カット-N-ペーストするとより助長)少しだけ短くして容易になるだろうidleIfNotMain()は、メインスレッドの場合はFalseを返すだけですが、そうでない場合はinspect(またはその他)を呼び出して呼び出し可能かどうかを調べ、idle_add()に渡してからTrueを返します。 argsを取得私は把握することができます。呼び出し可能にするのは簡単すぎないようです。 :-(

+0

まあ、気にしないでください。 idleIfNotMainはまさにデコレータのためのものです。 – Phil

関連する問題