Die Suche nach Funktionen, die in einem mit: Block
-
12-09-2019 - |
Frage
Hier ist ein Code von 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
Meine Frage ist: wie zum Teufel hat er das getan? Wie kann der Kontextmanager mit Block, den Umfang innerhalb der Zugriff? Hier ist eine grundlegende Vorlage für den Versuch, dies herauszufinden:
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
Lösung
Hier ist eine Art und Weise:
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()
Bearbeiten : stretched Code ein bisschen mehr, fügte eine Erklärung ...:
Anrufers Fangen Einheimischen an __exit__
ist einfach - heikler ist jene Einheimischen zu vermeiden, die bereits definiert wurden vor die with
Block, weshalb ich zur Haupt zwei lokale Funktionen hinzugefügt, die die with
ignorieren sollte. Ich bin nicht 100% zufrieden mit dieser Lösung, die ein wenig kompliziert aussieht, aber ich konnte nicht Gleichheit richtig mit entweder ==
oder is
Prüfung bekommen, so griff ich zu diesem ziemlich komplizierten Ansatz.
Außerdem habe ich eine Schleife (um stärker sicher, bevor die def
s zu machen / in / nach richtig behandelt werden) und eine Typprüfung und Funktionsaufruf, um sicherzustellen, dass die richtige Inkarnation testing
ist derjenige, der identifiziert ist (alles scheint gut zu funktionieren) - natürlich der Code geschrieben funktioniert nur, wenn die def
innerhalb der with
für eine Funktion aufrufbar ohne Argumente ist, ist es nicht schwer ist, die Signatur mit inspect
zu bekommen dagegen zu wehren (aber da ich bin tue das Gespräch nur zum Zweck der Überprüfung, dass die richtigen Funktionsobjekte identifiziert, störte ich nicht über diese letzte Verfeinerung; -).
Andere Tipps
Um Ihre Frage zu beantworten, ja, es ist Rahmen Innerlichkeit.
Aber die Syntax ich schaffen würde, das Gleiche zu tun ist,
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
Hier würde ich gui.button
als Dekorateur implementieren, die Schaltfläche Beispiel einige Parameter und Ereignisse gegeben zurück (obwohl es mir scheint nun, dass button = gui.button('click me!', mybutton_onclick
ist auch in Ordnung).
Ich würde auch verlassen gui.vertical
wie es da es ohne Selbstprüfung durchgeführt werden. Ich bin über seine Umsetzung nicht sicher, aber es kann es sich um gui.direction = gui.VERTICAL
Einstellung, so dass gui.label()
und andere es verwenden, um ihre Koordinaten bei der Berechnung.
Nun, wenn ich dies zu betrachten, ich glaube ich die Syntax versuchen würde:
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
(die Idee ist, dass ähnlich wie Etikett aus Text besteht, wird eine Schaltfläche aus Text und Funktion gemacht)