2009-08-10 10 views
9

がここにRichard Jones' Blogからいくつかのコードです:とで定義された関数を検索:ブロック

with gui.vertical: 
    text = gui.label('hello!') 
    items = gui.selection(['one', 'two', 'three']) 
    with gui.button('click me!'): 
     def on_click(): 
      text.value = items.value 
      text.foreground = red 

私の質問は:一体彼はこれをやったのか?コンテキストマネージャはwithブロック内のスコープにどのようにアクセスできますか?

答えて

11

はここに1つの方法です:ここではこれを理解しようとするための基本的なテンプレートがあります

from __future__ import with_statement 
import inspect 

class button(object): 
    def __enter__(self): 
    # keep track of all that's already defined BEFORE the `with` 
    f = inspect.currentframe(1) 
    self.mustignore = dict(f.f_locals) 

    def __exit__(self, exc_type, exc_value, traceback): 
    f = inspect.currentframe(1) 
    # see what's been bound anew in the body of the `with` 
    interesting = dict() 
    for n in f.f_locals: 
     newf = f.f_locals[n] 
     if n not in self.mustignore: 
     interesting[n] = newf 
     continue 
     anf = self.mustignore[n] 
     if id(newf) != id(anf): 
     interesting[n] = newf 
    if interesting: 
     print 'interesting new things: %s' % ', '.join(sorted(interesting)) 
     for n, v in interesting.items(): 
     if isinstance(v, type(lambda:None)): 
      print 'function %r' % n 
      print v() 
    else: 
     print 'nothing interesting' 

def main(): 
    for i in (1, 2): 
    def ignorebefore(): 
     pass 
    with button(): 
     def testing(i=i): 
     return i 
    def ignoreafter(): 
     pass 

main() 

編集は:コードはもう少し、いくつかの説明を追加伸ばし...:

呼び出し元のローカルユーザを__exit__にキャッチするのは簡単です。すでに定義されているローカルを避けるのは難しいですのブロックwithのブロックですwithが無視すべきローカル関数。私は少し複雑に見えるこの解決策に100%満足しているわけではありませんが、==またはisのどちらかで同等性テストを正しく行うことができませんでした。

私はループを追加しました(defの前/内/後が適切に処理されていることを確認するため)、タイプチェックと関数呼び出しにより、testingが正しいものであることを確認しましたそれは識別されている(すべてうまくいくようです) - もちろんコードは書かれている通り、withの中のdefは引数なしで呼び出し可能な関数であるため、それに対抗するためにinspectで署名を得ることは難しくありません正しい関数オブジェクトが識別されているかどうかを確認する目的でのみ呼び出しを行っていますが、この最後の改良については気にしませんでした。

+0

ラブリー、ありがとう。 – llimllib

+1

あなたは大歓迎です!取り組むのが楽しい問題だったので、それをポーズするためのtx ;-)。 –

+1

興味がある場合に備えて、私が与えたコードを使用してブログエントリを投稿しました: – llimllib

1

質問に答えるには、はい、それはフレームイントロスペクションです。

しかし、私は同じことが

with gui.vertical: 
    text = gui.label('hello!') 
    items = gui.selection(['one', 'two', 'three']) 
    @gui.button('click me!') 
    class button: 
     def on_click(): 
      text.value = items.value 
      text.foreground = red 

ですここで私はそれが今button = gui.button('click me!', mybutton_onclickがあるように私には見えるものの、いくつかのパラメータとイベント(特定のボタンインスタンスを返すデコレータとしてgui.buttonを実装し行うために作成します構文罰金も同様)。

イントロスペクションなしで実装できるため、gui.verticalもそのまま使用します。私はその実装についてはわかりませんが、それはを設定して、gui.label()などが座標を計算するのに使用するかもしれません。私はこれを見たとき

は今、私は構文を試してみたと思う:

with gui.vertical: 
     text = gui.label('hello!') 
     items = gui.selection(['one', 'two', 'three']) 

     @gui.button('click me!') 
     def button(): 
      text.value = items.value 
      foreground = red 

(同様にラベルがテキストから作られてどのように、ボタンはテキストから作られているということでアイデアと機能)

+0

しかし、なぜ "with gui.vertical"を使うのですか?その中のテキスト、アイテム、ボタンにアクセスするには、同じスタックイントロスペクションを実行する必要があります。 クラスMyLayout(gui.Vertical): テキスト= gui.label( 'こんにちは!') 右#etc私はあなたのような何かを確信していますか? とにかく、これはwithブロックの真剣に非標準的な乱用であることはよく知っています。私はちょうど彼がそれをやったか知りたかった。 少なくとも、それはwithブロックのクールな乱用だと思っていますか? – llimllib

+0

'with gui.vertical'を「要素を作成せず、このコンテキストで作成されたすべての要素が現在のポイント"。イントロスペクションなし。 –

関連する問題