2009-08-07 4 views
6

Errore di scoping molto bizzarro che non riesco nemmeno a vedere. All'interno di una funzione di aggiornamento, ho una funzione di supporto nidificato per ... help w/qualcosa:pygtk: variabile gratuita di riferimento prima dell'assegnazione nel campo di applicazione

def attach_row(ws,r1,r2): 
     es = [] 
     for i,w in enumerate(ws): 
      eb = gtk.EventBox() 
      a = gtk.Alignment(xalign=0.0,yalign=0.5) 
      a.add(w) 
      eb.add(a) 
      eb.set_style(self.rowStyle.copy()) 
      es.append(eb)     
      self.table.attach(eb, i, i+1, r1, r2, 
           xoptions=gtk.EXPAND|gtk.FILL, 
           yoptions=gtk.SHRINK) 

     def ene(_,ev): 
      for eb in es: 
       eb.set_state(gtk.STATE_PRELIGHT) 
     def lne(_,ev): 
      for eb in es: 
       eb.set_state(gtk.STATE_NORMAL) 
     for eb in es:     
      eb.connect('enter-notify-event', ene) 
      eb.connect('leave-notify-event', lne) 

questo funziona una volta ogni tanto, ma se la funzione di aggiornamento() corre troppo, alla fine ho capito:

for eb in es: 
NameError: free variable 'es' referenced before assignment in enclosing scope 

cosa sta causando questo? è sicuramente assegnato prima che queste funzioni vengano mai chiamate. Non è giusto? Accade qualcosa di bizzarro dove per qualche motivo viene chiamato l'ene() per una riga creata in precedenza mentre viene creato il nuovo, e viene sovrascritto lo spazio chiuso su es?

risposta

4

Piuttosto misterioso - sembra che la chiusura scompaia da sotto le funzioni interne. Mi chiedo se questo è legato a come pygtk detiene tali funzioni di callback (non ho familiarità con i suoi interni). Per provare a sondare per quello - cosa succede se aggiungi anche ene e lne a un elenco globale alla fine di attach_row, giusto per assicurarti che siano tenuti "normalmente" da qualche parte così che la loro chiusura sopravviva - il problema persiste questo caso?

Se lo fa, devo ammettere che il problema è TROPPO misterioso e concordo con la risposta precedente, suggerendo, come soluzione, l'uso di callables che mantengono il loro stato in un modo più chiaro (suggerirei due metodi associati di un'istanza di classe, poiché condividono il loro stato, ma due istanze di una singola classe con __call__ e la ricezione dello stato da impostare e l'elenco di caselle di eventi nel suo __init__ è sicuramente anche ragionevole - avendo due classi separate IMHO sarebbe un po ' esagerazione;-).

+0

hehe, vero. In realtà mi sono reso conto di avere un modo più sano per farlo: invece di rimuovere e allegare molte di queste righe, creo solo un set di esse e cambio i widget al loro interno. Una nota, però: ho provato a passare "es" come dati utente a quelle funzioni ene e lne. Quello che è successo è che non ho più avuto l'errore NameError, ma i widget non evidenziavano affatto. Qualcosa si stava ancora perdendo da qualche parte. Se questo torna di nuovo proverò l'idea di classe. – Claudiu

+0

ancora meglio - usa un VBox, metti un box per evento per riga, e poi usa un sizegroup per allineare le colonne – Claudiu

+0

sì, questo è accaduto anche in altre situazioni. penso sia la stranezza di Python 2.5. non ho mai trovato una risposta – Claudiu

0

non hanno abbastanza punti per lasciare questo come un commento (appena registrato) ...

  • variabile No 'es' a livello globale o in un ambito più elevato?
  • attach_row non è anche una funzione annidata?
  • NameError fa riferimento all'eccezione per la linea del loop nelle funzioni ene o lne?

Una possibile, ma icky, soluzione potrebbe essere quella di rendere le classi ene e lne che sono istanziate e richiamabili come funzioni tramite un metodo __call __().