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
War es hilfreich?

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

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top