ブロック:付きで定義された関数を見つけます
-
12-09-2019 - |
質問
ここでリチャード・ジョーンズのブログのからいくつかのコードがあります:
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
私の質問は:一体彼はこれをやったのか?どのようにコンテキストマネージャは、ブロックと内部のスコープにアクセスすることができますか?ここではこれを理解しようとするための基本的なテンプレートです。
from __future__ import with_statement
class button(object):
def __enter__(self):
#do some setup
pass
def __exit__(self, exc_type, exc_value, traceback):
#XXX: how can we find the testing() function?
pass
with button():
def testing():
pass
解決
ここに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
は無視すべき主な2つのローカルな機能を追加した理由です。のwith
ブロック、前にすでに定義されていたものを地元の人々を避けています。私は少し複雑に見えます。このソリューション、100%満足していないんだけど、私は==
またはis
のいずれかで正しいテスト平等を得ることができなかったので、私は、この複雑なアプローチに頼っています。
私もループを追加しました(/は、後に適切に処理されている範囲内/ def
s前より強く確認します)と、型チェックと関数呼び出しは、確認するためにtesting
の右の化身は、特定されています一つです(すべてが正常に動作するようです) - もちろん書かれたように、コードはdef
内部with
は、引数なしで呼び出し可能な機能のためであれば、それはそれに対して病棟にinspect
で署名を取得することは難しいことではありません動作します(が、私はだので、唯一の右の関数オブジェクトが識別されていることを確認する目的のためにコールをやって、私はこの最後の微調整については気にしませんでした; - )
他のヒント
あなたの質問に答えるために、はい、それはフレームのイントロスペクションです。
しかし、私は同じことを行うために作成し構文は次のとおりです。
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
ここで私は(gui.button
が同様に罰金であることを今私には見えるが)いくつかのパラメータとイベントの特定のボタンインスタンスを返すデコレータとしてbutton = gui.button('click me!', mybutton_onclick
を実装します。
私はまたgui.vertical
を残すでしょう。私はその実装についてはよく分からないんだけど、gui.direction = 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
タグ(アイデアは、同様にラベルがテキストから作られてどのように、ボタンはテキストや機能から作られていることです)