2011-01-21 12 views
7

Di ', ho un certo margine con le variabili, e una funzione chiamata in questo ambito vuole cambiare alcune variabili immutabili:Accesso al campo di applicazione esterna in Python 2.6

 
def outer(): 
    s = 'qwerty' 
    n = 123 
    modify() 

def modify(): 
    s = 'abcd' 
    n = 456 

è possibile in qualche modo per accedere al campo di applicazione esterna? Qualcosa come le variabili nonlocal da Py3k.

Certo che posso fare s,n = modify(s,n) in questo caso, ma cosa succede se ho bisogno di un 'iniezione' generico che esegue lì e deve essere in grado di riassegnare a variabili arbitrarie?

devo prestazioni in mente, quindi, se possibile, l'ispezione eval cornice & dello stack non è il benvenuto :)


UPD: E 'impossibile. Periodo. Tuttavia, ci sono alcune opzioni su come accedere alle variabili nell'ambito esterno:

  1. Utilizzare le globali. Tra l'altro, func.__globals__ è un dizionario mutabile;)
  2. variabili Conservare in dict/class-instance/qualsiasi altro contenitore mutevole
  3. Dare variabili come argomenti & farli tornare come una tupla: a,b,c = innerfunc(a,b,c)
  4. Inject altra funzione di bytecode. Questo è possibile con il modulo python byteplay.
+1

Non è così che funziona lo scoping. Chiedi di accedere a un ambito su un diverso stackframe. Sarebbe ** molto ** confuso se l'ambito consentisse ciò che provate qui, pensate alla ricorsione della coda riscritta nei loop. Quindi l'ottimizzazione del codice cambierebbe improvvisamente il significato di un programma, questo non accadrà mai. – Tino

risposta

3

Questo è non how nonlocal opere. Non fornisce scope dinamico (che è solo un enorme PITA in attesa di accadere e ancora più raramente utile della tua caratteristica "cattiva" media). Corregge solo lo scoping lessicale.

In ogni caso, non puoi fare quello che hai in mente (e direi che questa è una buona cosa). Non c'è nemmeno un trucco sporco ma facile (e anche se ci siamo arrivati: tali hack non sono scoraggiati perché generalmente si comportano un po 'peggio!). Basta dimenticarlo e risolvere il vero problema in modo corretto (non lo hai nominato, quindi non possiamo dire nulla su questo).

Il più vicino possibile è definire un oggetto che trasporta tutto ciò che si desidera condividere e passarlo esplicitamente (ad es. Ma questo è relativamente macchinoso da fare ovunque, e comunque hackery (anche se meglio dell'ambito dinamico, perché "esplicito è meglio di implicito").

7

Definire le variabili al di fuori delle funzioni e utilizzare la parola chiave global.

s, n = "", 0 

def outer(): 
    global n, s 
    n = 123 
    s = 'qwerty' 
    modify() 

def modify(): 
    global n, s 
    s = 'abcd' 
    n = 456 
+1

Sostituisci 'and' con' xor' affinché funzioni. Riscrivi da zero per un buon consiglio. – delnan

+0

@delnan, mi dispiace, ma ??? – orlp

+0

Intende "definirli all'esterno, o usare' global', ma non entrambi ". – gotgenes

3

Le opzioni disponibili sono da usare global variabili,

s = None 
n = None 

def outer(self): 
    global s 
    global n 
    s = 'qwerty' 
    n = 123 
    modify() 

def modify(self): 
    global s 
    global n 
    s = 'abcd' 
    n = 456 

o definire quelli come metodi e utilizzare una variabile di classe o istanza.

class Foo(object): 
    def __init__(self): 
     self.s = None 
     self.n = None 

    def outer(self): 
     self.s = 'qwerty' 
     self.n = 123 
     self.modify() 

    def modify(self): 
     self.s = 'abcd' 
     self.n = 456 
7

A volte corro attraverso codice come questo.Una funzione annidata modifica un oggetto mutabile invece di assegnare ad un nonlocal:

def outer(): 
    s = [4] 
    def inner(): 
     s[0] = 5 
    inner() 
+1

È interessante. Brutto, ma interessante. – gotgenes

+1

'outer.s = 4' etc –

+3

È possibile digitare outer.s = 4, ma questo assegnerà un attributo alla funzione outer(). Non è lo stesso che assegnare alla variabile locale chiamata s. – joeforker

1

probabilmente si può anche fare questo (non dicendo che è a destra);

definire una funzione che restituisce un array con le righe in questo modo

["a = qwerty","n = 123"] 

Poi fare nel campo di applicazione è necessario il Vars

for row in array: 
    eval(row) 

questo è maledettamente hacky però.

+0

Penso che intendiate 'exec (row)'; eval è solo per le espressioni – Ord

Problemi correlati