Domanda

Ecco un po 'di codice da 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

La mia domanda è: come diavolo ha fatto questo? Come si può accedere al direttore contesto l'ambito all'interno del blocco con? Ecco un modello di base per cercare di capire questo:

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
È stato utile?

Soluzione

Ecco un modo:

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

Modifica : allungato codice un po 'di più, ha aggiunto qualche spiegazione ...:

Facendo i locali del chiamante a __exit__ è facile - più difficile è di evitare quei locali che sono stati già definiti prima il blocco with, che è il motivo per cui ho aggiunto ai due principali funzioni locali che il with dovrebbe ignorare. Io non sono soddisfatto al 100% di questa soluzione, che sembra un po 'complicato, ma non ho potuto ottenere l'uguaglianza testare il corretto sia con == o is, così ho fatto ricorso a questo approccio piuttosto complicata.

Ho anche aggiunto un loop (per rendere più forte che i defs prima / entro / dopo vengono adeguatamente trattati) e di un tipo di controllo e la funzione di chiamata per assicurarsi il diritto incarnazione testing è quello che è identificato (tutto sembra funzionare bene) - naturalmente il codice come scritto funziona solo se il def all'interno del with è per una funzione richiamabile senza argomenti, non è difficile per ottenere la firma con inspect per scongiurare contro quella (ma visto che sono facendo la chiamata solo per lo scopo di verificare che gli oggetti funzione di destra sono identificati, non mi sono preoccupato di questo ultimo perfezionamento; -).

Altri suggerimenti

Per rispondere alla tua domanda, sì, è cornice introspezione.

Ma la sintassi vorrei creare a fare la stessa cosa è

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

A questo punto vorrei implementare gui.button come decoratore che restituisce un'istanza di pulsante dato alcuni parametri ed eventi (anche se mi sembra ora che button = gui.button('click me!', mybutton_onclick va bene così).

Vorrei anche lasciare gui.vertical come lo è dal momento che può essere attuato senza l'introspezione. Io non sono sicuro circa la sua attuazione, ma si può comprendere la definizione gui.direction = gui.VERTICAL in modo che gui.label() e altri lo utilizzano nel calcolo le loro coordinate.

Ora, quando guardo questo, penso che mi piacerebbe provare la sintassi:

    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

(l'idea è che in modo simile a come etichetta è fatto di testo, un pulsante è fatto di testo e funzione)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top