Uso della parola chiave "globale" in Python


285

Quello che capisco leggendo la documentazione è che Python ha uno spazio dei nomi separato per le funzioni e se voglio usare una variabile globale in quella funzione, devo usare global.

Sto usando Python 2.7 e ho provato questo piccolo test

>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
...     return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'

Sembra che le cose funzionino bene anche senza global. Sono stato in grado di accedere alla variabile globale senza alcun problema.

Mi sto perdendo qualcosa? Inoltre, ciò che segue è dalla documentazione di Python:

I nomi elencati in un'istruzione globale non devono essere definiti come parametri formali o in una destinazione di controllo del ciclo for, definizione di classe, definizione di funzione o istruzione di importazione.

Sebbene i parametri formali e la definizione della classe abbiano senso per me, non sono in grado di comprendere la limitazione per la definizione del target di controllo del loop e la definizione della funzione.


1
Penso che tu sia confuso con php che richiede l'uso della parola chiave globale - i documenti di Python lo confermano - fondamentalmente se non è definito nel contesto locale è trattato come globale
tobyodavies

11
Fai attenzione con la tua formulazione: Python non ha uno spazio dei nomi separato per le funzioni (ciò significherebbe che potresti avere def foo(): ...e foo = ...allo stesso tempo). Crea un nuovo ambito per ogni chiamata di funzione. (Ma in che modo differisce da qualsiasi altra lingua di alto livello in remoto nel mondo?)

Risposte:


366

La parola chiave globalè utile solo per modificare o creare variabili globali in un contesto locale, sebbene la creazione di variabili globali sia raramente considerata una buona soluzione.

def bob():
    me = "locally defined"    # Defined only in local context
    print(me)

bob()
print(me)     # Asking for a global variable

Quanto sopra ti darà:

locally defined
Traceback (most recent call last):
  File "file.py", line 9, in <module>
    print(me)
NameError: name 'me' is not defined

Mentre se usi l' globalistruzione, la variabile diventerà disponibile "al di fuori" dell'ambito della funzione, diventando effettivamente una variabile globale.

def bob():
    global me
    me = "locally defined"   # Defined locally but declared as global
    print(me)

bob()
print(me)     # Asking for a global variable

Quindi il codice sopra ti darà:

locally defined
locally defined

Inoltre, a causa della natura di Python, è possibile utilizzare anche globalper dichiarare funzioni, classi o altri oggetti in un contesto locale. Anche se lo sconsiglio dal momento che provoca incubi se qualcosa va storto o necessita di debug.


59
"globale" in questo contesto sembra essere diverso da altre lingue considerato "globale". In Python un riferimento "globale" è ancora nei confini del modulo e dovrebbe essere referenziato dall'esterno di quel modulo come "module.global_var" piuttosto che semplicemente "global_var" come ci si potrebbe aspettare.
succo

17
@juice - In Python non esiste nulla di assoluto globalsdefinito automaticamente in tutti gli spazi dei nomi (per fortuna). Come hai giustamente sottolineato, un globale è associato a uno spazio dei nomi all'interno di un modulo, tuttavia può essere importato in un altro modulo come from module import variableo import module.variable. Nel primo caso, l'importazione renderebbe la variabile accessibile variablesenza richiedere riferimento come module.. Se è considerato globale nell'ambito del modulo dipenderà da dove viene importato. Vedi anche nonlocalcome nuova parola chiave relativa all'ambito in Python 3.
unode

3
Potresti spiegare perché le variabili globali non sono una buona soluzione? Lo sento spesso, ma nel mio progetto attuale sembrano fare esattamente ciò di cui ho bisogno. C'è qualcosa di più sinistro a cui non ho pensato?
Robin Newhouse,

5
@RobinNewhouse Ci sono alcune domande su SO che già trattano questo argomento e altri articoli non SO .
unode,

213

Mentre puoi accedere alle variabili globali senza la globalparola chiave, se vuoi modificarle devi usare la globalparola chiave. Per esempio:

foo = 1
def test():
    foo = 2 # new local foo

def blub():
    global foo
    foo = 3 # changes the value of the global foo

Nel tuo caso, stai solo accedendo all'elenco sub.


3
Con un avvertimento: foo = 3senza lavori globali, ma foo viene nuovamente definito localmente nell'ambito della blubfunzione e non modifica la variabile foo originale. Questo è stato abbastanza confuso per me.
chhantyal,

1
@chhantyal se per opere intendi che non genera un errore, hai ragione, ma nel contesto di Ivo Wetzel non funzionerebbe come previsto. Ci sono usi per tale comportamento, ma spesso non è quello che vuole il programmatore.
democidista

77

Questa è la differenza tra accedere al nome e vincolarlo in un ambito.

Se stai solo cercando una variabile per leggerne il valore, hai accesso all'ambito globale e locale.

Tuttavia, se si assegna a una variabile il cui nome non è nell'ambito locale, si vincola quel nome a questo ambito (e se quel nome esiste anche come globale, lo si nasconderà).

Se si desidera essere in grado di assegnare al nome globale, è necessario indicare al parser di utilizzare il nome globale anziché associare un nuovo nome locale, che è ciò che fa la parola chiave "globale".

Associare un punto qualsiasi all'interno di un blocco fa sì che il nome ovunque in quel blocco venga associato, il che può causare conseguenze piuttosto strane (ad esempio UnboundLocalError che appare improvvisamente nel codice precedentemente funzionante).

>>> a = 1
>>> def p():
    print(a) # accessing global scope, no binding going on
>>> def q():
    a = 3 # binding a name in local scope - hiding global
    print(a)
>>> def r():
    print(a) # fail - a is bound to local scope, but not assigned yet
    a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
  File "<pyshell#35>", line 1, in <module>
    r()
  File "<pyshell#32>", line 2, in r
    print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>> 

molto controintuitivo, difficile da credere che si tratti di un codice pitone valido
PlsWork,

52

Le altre risposte rispondono alla tua domanda. Un'altra cosa importante da sapere sui nomi in Python è che sono locali o globali in base all'ambito.

Considera questo, ad esempio:

value = 42

def doit():
    print value
    value = 0

doit()
print value

Probabilmente puoi immaginare che l' value = 0istruzione verrà assegnata a una variabile locale e non influirà sul valore della stessa variabile dichiarata all'esterno della doit()funzione. Potresti essere più sorpreso di scoprire che il codice sopra non verrà eseguito. L'istruzione print valueall'interno della funzione produce unUnboundLocalError.

Il motivo è che Python ha notato che, altrove nella funzione, si assegna il nome valuee inoltre valuenon è stato dichiarato da nessuna parte global. Questo lo rende una variabile locale. Ma quando si tenta di stamparlo, il nome locale non è stato ancora definito. Python in questo caso non ricorre alla ricerca del nome come variabile globale, come fanno alcune altre lingue. In sostanza, non è possibile accedere a una variabile globale se è stata definita una variabile locale con lo stesso nome in qualsiasi punto della funzione.


1
Grazie per averlo segnalato. Pertanto, finché l'ambito locale non viene assegnato a un nome esistente al di fuori di esso, i riferimenti nell'ambito locale utilizzeranno il nome esterno. Tuttavia, se in qualsiasi parte della funzione assegnate a quel nome, i riferimenti in tale ambito locale, anche prima dell'assegnazione locale, non guardano all'esterno.
Dmitry Minkovsky,

1
Esatto, ce l'hai. global(o nonlocalin Python 3.x) ignora questo comportamento e consente di riassegnare il nome esterno.
kindall

2
In altre lingue, questo sembra essere chiamato "sollevamento", come ad esempio: github.com/shichuan/javascript-patterns/blob/master/…
Dmitry Minkovsky

Per aggiungere la beffa al danno, le variabili dichiarate con la nuova parola chiave JavaScript nonlet vengono sollevate.
kindall

È più veloce accedere a una variabile globale dichiarata con globalo non ha importanza?
mato,

14

L'accesso a un nome e l'assegnazione di un nome sono diversi. Nel tuo caso, stai solo accedendo a un nome.

Se si assegna a una variabile all'interno di una funzione, si presume che tale variabile sia locale a meno che non venga dichiarata globale. In assenza di ciò, si presume che sia globale.

>>> x = 1         # global 
>>> def foo():
        print x       # accessing it, it is global

>>> foo()
1
>>> def foo():   
        x = 2        # local x
        print x 

>>> x            # global x
1
>>> foo()        # prints local x
2

7
  • Puoi accedere a parole chiave globali senza parola chiave global
  • Per poterli modificare è necessario dichiarare esplicitamente che la parola chiave è globale. In caso contrario, la parola chiave verrà dichiarata nell'ambito locale.

Esempio:

words = [...] 

def contains (word): 
    global words             # <- not really needed
    return (word in words) 

def add (word): 
    global words             # must specify that we're working with a global keyword
    if word not in words: 
        words += [word]

2

Si presume che qualsiasi variabile dichiarata al di fuori di una funzione sia globale, è solo quando si dichiarano dall'interno di funzioni (eccetto i costruttori) che è necessario specificare che la variabile è globale.


1

Questo è spiegato bene nelle FAQ di Python

Quali sono le regole per le variabili locali e globali in Python?

In Python, le variabili a cui viene fatto riferimento solo all'interno di una funzione sono implicitamente globali. Se a una variabile viene assegnato un valore in qualsiasi punto del corpo della funzione, si presume che sia un valore locale se non esplicitamente dichiarato globale.

Anche se all'inizio è un po 'sorprendente, un attimo di considerazione lo spiega. Da un lato, la richiesta globaldi variabili assegnate fornisce una barra contro gli effetti collaterali indesiderati. D'altra parte, se globalfosse richiesto per tutti i riferimenti globali, saresti sempre in uso global. Dovresti dichiarare come globalogni riferimento a una funzione integrata o a un componente di un modulo importato. Questo disordine vanificherebbe l'utilità della globaldichiarazione per identificare gli effetti collaterali.

https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-python


0

Significa che non dovresti fare quanto segue:

x = 1

def myfunc():
  global x

  # formal parameter
  def localfunction(x):
    return x+1

  # import statement
  import os.path as x

  # for loop control target
  for x in range(10):
    print x

  # class definition
  class x(object):
    def __init__(self):
      pass

  #function definition
  def x():
    print "I'm bad"

ikostia sta elencando tutte le cose che non puoi usare 'x' per aver usato globale - docs.python.org/reference/…
pycruft

1
@Unode: sto solo dimostrando tutti i casi che NikhilRathod ha citato nella sua citazione.
ikostia,

0

Global rende la variabile "Global"

def out():
    global x
    x = 1
    print(x)
    return


out()

print (x)

Questo fa 'x' agire come una normale variabile al di fuori della funzione. Se si eliminasse il globale, si darebbe un errore poiché non è possibile stampare una variabile all'interno di una funzione.

def out():
     # Taking out the global will give you an error since the variable x is no longer 'global' or in other words: accessible for other commands
    x = 1
    print(x)
    return


out()

print (x)
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.