Qual è la differenza tra globals (), locals () e vars ()?


146

Qual è la differenza tra globals(), locals()e vars()? Cosa ritornano? Gli aggiornamenti ai risultati sono utili?


si può aggiornare uno di questi in Python 3 e far funzionare lo script?
Charlie Parker,

Risposte:


172

Ognuno di questi restituisce un dizionario:

  • globals() restituisce sempre il dizionario dello spazio dei nomi del modulo
  • locals() restituisce sempre un dizionario dello spazio dei nomi corrente
  • vars()restituisce un dizionario dello spazio dei nomi corrente (se chiamato senza argomento) o il dizionario dell'argomento.

localse varspotrebbe usare qualche spiegazione in più. Se locals()viene chiamato all'interno di una funzione, aggiorna un dict con i valori dello spazio dei nomi delle variabili locali correnti (più eventuali variabili di chiusura) a partire da quel momento e lo restituisce. Più chiamate a locals()nello stesso frame dello stack restituiscono ogni volta lo stesso dict: è collegato all'oggetto frame dello stack come suo f_localsattributo. I contenuti del dict vengono aggiornati su ogni locals()chiamata e ogni f_localsaccesso agli attributi, ma solo su tali chiamate o accessi agli attributi. Non si aggiorna automaticamente quando le variabili sono assegnate e l'assegnazione delle voci nel dict non assegnerà le variabili locali corrispondenti:

import inspect

def f():
    x = 1
    l = locals()
    print(l)
    locals()
    print(l)
    x = 2
    print(x, l['x'])
    l['x'] = 3
    print(x, l['x'])
    inspect.currentframe().f_locals
    print(x, l['x'])

f()

ci da:

{'x': 1}
{'x': 1, 'l': {...}}
2 1
2 3
2 2

Il primo print(l)mostra solo una 'x'voce, perché l'assegnazione lavviene dopo la locals()chiamata. Il secondo print(l), dopo aver richiamato di locals()nuovo, mostra una lvoce, anche se non abbiamo salvato il valore di ritorno. La terza e la quarta prints mostrano che l'assegnazione delle variabili non si aggiorna le viceversa, ma dopo l'accesso f_locals, le variabili locali vengono locals()nuovamente copiate .

Due note:

  1. Questo comportamento è specifico di CPython: altri Python potrebbero consentire agli aggiornamenti di tornare automaticamente allo spazio dei nomi locale.
  2. In CPython 2.x è possibile farlo funzionare inserendo una exec "pass"linea nella funzione. In questo modo la funzione passa a una modalità di esecuzione più vecchia e più lenta che utilizza il locals()comando come rappresentazione canonica delle variabili locali.

Se locals()viene chiamato al di fuori di una funzione, restituisce il dizionario effettivo che è lo spazio dei nomi corrente. Ulteriori modifiche allo spazio dei nomi si riflettono nel dizionario e le modifiche al dizionario si riflettono nello spazio dei nomi:

class Test(object):
    a = 'one'
    b = 'two'
    huh = locals()
    c = 'three'
    huh['d'] = 'four'
    print huh

ci da:

{
  'a': 'one',
  'b': 'two',
  'c': 'three',
  'd': 'four',
  'huh': {...},
  '__module__': '__main__',
}

Finora, tutto ciò di cui ho parlato locals()è vero anche per vars()... ecco la differenza: vars()accetta un singolo oggetto come argomento, e se gli dai un oggetto restituisce l' __dict__oggetto. Per un oggetto tipico, __dict__è dove è archiviata la maggior parte dei suoi dati di attributo. Ciò include variabili di classe e moduli globali:

class Test(object):
    a = 'one'
    b = 'two'
    def frobber(self):
        print self.c
t = Test()
huh = vars(t)
huh['c'] = 'three'
t.frobber()

che ci dà:

three

Si noti che una funzione __dict__è il suo spazio dei nomi degli attributi, non le variabili locali. Non avrebbe senso che una funzione __dict__memorizzi le variabili locali, poiché la ricorsione e il multithreading significano che possono esserci più chiamate contemporaneamente a una funzione, ognuna con i propri locali:

def f(outer):
    if outer:
        f(False)
        print('Outer call locals:', locals())
        print('f.__dict__:', f.__dict__)
    else:
        print('Inner call locals:', locals())
        print('f.__dict__:', f.__dict__)

f.x = 3

f(True)

che ci dà:

Inner call locals: {'outer': False}
f.__dict__: {'x': 3}
Outer call locals: {'outer': True}
f.__dict__: {'x': 3}

Qui, si fchiama ricorsivamente, quindi le chiamate interne ed esterne si sovrappongono. Ognuno vede le proprie variabili locali quando chiama locals(), ma entrambe le chiamate vedono lo stesso f.__dict__e f.__dict__non contiene variabili locali.


4
La parte "e le eventuali assegnazioni al dizionario non si riflettono nello spazio dei nomi locale reale" potrebbe essere formulata in modo un po 'definito .
Sven Marnach,

Stranamente, puoi usare le variabili aggiunte a un vars()o locals()dizionario chiamato all'interno di una funzione se lo usi eval(). Ad esempio: def test(): huh = locals(); huh['d'] = 4; print eval('d')stampa 4 quando test()viene eseguito!
Mark Mikofski,

1
In realtà l'assegnazione al dict(restituito da locals()) sembra riflettersi nello spazio dei nomi locale e le modifiche allo spazio dei nomi locale si riflettono nel dict(nel mio pitone). L'unica cosa è che le specifiche non garantiscono questo comportamento.
stelle il

L' uso dell'ambito del nome del termine mi sembra più facile dello spazio dei nomi .
scambio eccessivo del

1
@overexchange: import thise in googlesite:docs.python.org namespace
Ethan Furman,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.