Usar variables globales en una función


3116

¿Cómo puedo crear o usar una variable global en una función?

Si creo una variable global en una función, ¿cómo puedo usar esa variable global en otra función? ¿Necesito almacenar la variable global en una variable local de la función que necesita su acceso?

Respuestas:


4249

Puede usar una variable global en otras funciones declarándola como globalen cada función que le asigne:

globvar = 0

def set_globvar_to_one():
    global globvar    # Needed to modify global copy of globvar
    globvar = 1

def print_globvar():
    print(globvar)     # No need for global declaration to read value of globvar

set_globvar_to_one()
print_globvar()       # Prints 1

Me imagino que la razón es que, dado que las variables globales son tan peligrosas, Python quiere asegurarse de que realmente sepas con qué estás jugando al requerir explícitamente la globalpalabra clave.

Vea otras respuestas si desea compartir una variable global entre módulos.


839
Es una exageración extrema referirse a los globales como "muy peligrosos". Los globales están perfectamente bien en todos los idiomas que han existido y existirán. Ellos tienen su lugar. Lo que debería haber dicho es que pueden causar problemas si no tiene idea de cómo programar.
Anthony

208
Creo que son bastante peligrosos. Sin embargo, en Python las variables "globales" son en realidad de nivel de módulo, lo que resuelve muchos problemas.
Fábio Santos

247
No estoy de acuerdo con que la razón por la que Python requiere la globalpalabra clave sea porque los globales son peligrosos. Más bien, se debe a que el lenguaje no requiere que declare explícitamente las variables y automáticamente asume que una variable que asigna tiene un alcance de función a menos que le indique lo contrario. La globalpalabra clave es el medio que se proporciona para indicarle lo contrario.
Nate CK

77
@avgvstvs: Y si está implementando el mismo programa sin globales, todavía tiene la misma cantidad de rutas de código. El argumento que ha hecho no es uno contra los globales.
Carreras ligeras en órbita el

13
@LightnessRacesinOrbit No entiendo tu punto. Si elimina una variable global, elimina el factor de complicación en que ahora, las funciones arbitrarias ya no pueden alterar el estado del programa , en varios puntos de la ejecución, alterando así la ejecución de una manera que de otra manera sería imperceptible para otras funciones que dependen de esa variable. Usted ya no tiene que perder de vista, "¿Se f2()cambian de estado por lo que ahora f3()podría hacer algo inesperado Las funciones pueden ahora operar agnóstico a otro programa externo?.
AVGVSTVS

775

Si entiendo su situación correctamente, lo que está viendo es el resultado de cómo Python maneja los espacios de nombres locales (funciones) y globales (módulos).

Digamos que tienes un módulo como este:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

Es posible que espere que esto imprima 42, pero en su lugar imprime 5. Como ya se mencionó, si agrega una globaldeclaración ' ' func1(), func2()imprimirá 42.

def func1():
    global myGlobal
    myGlobal = 42

Lo que está sucediendo aquí es que Python asume que cualquier nombre asignado a , en cualquier lugar dentro de una función, es local a esa función a menos que se indique explícitamente lo contrario. Si solo lee un nombre y el nombre no existe localmente, intentará buscar el nombre en cualquier ámbito que contenga (por ejemplo, el alcance global del módulo).

Cuando asigna 42 al nombre myGlobal, por lo tanto, Python crea una variable local que sombrea la variable global del mismo nombre. Ese local queda fuera de alcance y se recolecta basura cuando func1()regresa; Mientras tanto, func2()nunca puede ver otra cosa que no sea el nombre global (sin modificar). Tenga en cuenta que esta decisión de espacio de nombres ocurre en el momento de la compilación, no en tiempo de ejecución: si tuviera que leer el valor de myGlobalinside func1()antes de asignarlo, obtendría un UnboundLocalError, porque Python ya ha decidido que debe ser una variable local pero aún no ha tenido ningún valor asociado. Pero al usar la globalinstrucción ' ', le dice a Python que debe buscar el nombre en otro lugar en lugar de asignarlo localmente.

(Creo que este comportamiento se originó en gran medida a través de una optimización de los espacios de nombres locales; sin este comportamiento, la VM de Python necesitaría realizar al menos tres búsquedas de nombres cada vez que se asigna un nuevo nombre dentro de una función (para asegurarse de que el nombre no t ya existe en el módulo / nivel integrado), lo que ralentizaría significativamente una operación muy común).


Usted mencionó que la decisión del espacio de nombres ocurre en el momento de la compilación , no creo que sea cierto. por lo que sé, la compilación de Python solo comprueba si hay un error de sintaxis, no un error de nombre, intente este ejemplo def A (): x + = 1 , si no lo ejecuta, no dará UnboundLocalError , verifique gracias
watashiSHUN

1
Es común usar una letra mayúscula para variables globales comoMyGlobal = 5
Vassilis

3
@watashiSHUN: La decisión espacio de nombres no sucederá en tiempo de compilación. Decidir que xes local es diferente de verificar en tiempo de ejecución si el nombre local estaba vinculado a un valor antes de que se use la primera vez.
BlackJack el

99
@Vassilis: Es común a mayúsculas todas las letras: MY_GLOBAL = 5. Consulte la Guía de estilo para el código Python .
BlackJack

223

Es posible que desee explorar la noción de espacios de nombres . En Python, el módulo es el lugar natural para los datos globales :

Cada módulo tiene su propia tabla de símbolos privada, que todas las funciones definidas en el módulo utilizan como tabla de símbolos global. Por lo tanto, el autor de un módulo puede usar variables globales en el módulo sin preocuparse por choques accidentales con las variables globales de un usuario. Por otro lado, si sabe lo que está haciendo, puede tocar las variables globales de un módulo con la misma notación utilizada para referirse a sus funciones modname.itemname,.

Aquí se describe un uso específico de global-in-a-module: ¿cómo comparto variables globales entre módulos? , y para completar, los contenidos se comparten aquí:

La forma canónica de compartir información entre los módulos dentro de un solo programa es crear un módulo de configuración especial (a menudo llamado config o cfg ). Simplemente importe el módulo de configuración en todos los módulos de su aplicación; el módulo estará disponible como nombre global. Como solo hay una instancia de cada módulo, los cambios realizados en el objeto del módulo se reflejan en todas partes. Por ejemplo:

Archivo: config.py

x = 0   # Default value of the 'x' configuration setting

Archivo: mod.py

import config
config.x = 1

Archivo: main.py

import config
import mod
print config.x

1
por una razón que no me gusta, config.x ¿puedo deshacerme de él? Vine con x = lambda: config.xy luego tengo el nuevo valor x(). por alguna razón, tener a = config.xno me sirve de nada.
vladosaurus

3
@vladosaurus from config import xresuelve eso?
jhylands

93

Python utiliza una heurística simple para decidir desde qué ámbito debe cargar una variable, entre local y global. Si aparece un nombre de variable en el lado izquierdo de una asignación, pero no se declara global, se supone que es local. Si no aparece en el lado izquierdo de una tarea, se supone que es global.

>>> import dis
>>> def foo():
...     global bar
...     baz = 5
...     print bar
...     print baz
...     print quux
... 
>>> dis.disassemble(foo.func_code)
  3           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (baz)

  4           6 LOAD_GLOBAL              0 (bar)
              9 PRINT_ITEM          
             10 PRINT_NEWLINE       

  5          11 LOAD_FAST                0 (baz)
             14 PRINT_ITEM          
             15 PRINT_NEWLINE       

  6          16 LOAD_GLOBAL              1 (quux)
             19 PRINT_ITEM          
             20 PRINT_NEWLINE       
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE        
>>> 

Vea cómo baz, que aparece en el lado izquierdo de una tarea en foo(), es la única LOAD_FASTvariable.


12
La heurística busca operaciones vinculantes . La asignación es una de esas operaciones, importando otra. Pero el objetivo de un forbucle y el nombre después de asen withy las exceptdeclaraciones también están vinculados.
Martijn Pieters

@MartijnPieters Para el nombre después asen una exceptcláusula, esto no era obvio para mí. Pero se elimina automáticamente para ahorrar memoria.
Robert

1
@Robert: no para guardar memoria, sino para evitar crear una referencia circular, que puede provocar pérdidas de memoria. Esto se debe a que una excepción hace referencia a un rastreo, y el rastreo hace referencia a cada espacio de nombres local y global a lo largo de toda la pila de llamadas, incluido el as ...destino en el controlador de excepciones.
Martijn Pieters

62

Si desea hacer referencia a una variable global en una función, puede usar la palabra clave global para declarar qué variables son globales. No tiene que usarlo en todos los casos (como alguien aquí afirma incorrectamente): si el nombre al que se hace referencia en una expresión no se puede encontrar en el ámbito local o en los ámbitos en las funciones en las que se define esta función, se busca entre variables

Sin embargo, si asigna a una nueva variable no declarada como global en la función, se declara implícitamente como local y puede eclipsar cualquier variable global existente con el mismo nombre.

Además, las variables globales son útiles, al contrario de algunos fanáticos de OOP que afirman lo contrario, especialmente para scripts más pequeños, donde OOP es excesivo.


Absolutamente re. fanáticos La mayoría de los usuarios de Python lo usan para crear secuencias de comandos y crean pequeñas funciones para separar pequeños fragmentos de código.
Paul Uszak

51

Si creo una variable global en una función, ¿cómo puedo usar esa variable en otra función?

Podemos crear un global con la siguiente función:

def create_global_variable():
    global global_variable # must declare it to be a global first
    # modifications are thus reflected on the module's global scope
    global_variable = 'Foo' 

Escribir una función en realidad no ejecuta su código. Entonces llamamos a la create_global_variablefunción:

>>> create_global_variable()

Usando globals sin modificación

Simplemente puede usarlo, siempre y cuando no espere cambiar a qué objeto apunta:

Por ejemplo,

def use_global_variable():
    return global_variable + '!!!'

y ahora podemos usar la variable global:

>>> use_global_variable()
'Foo!!!'

Modificación de la variable global desde una función.

Para apuntar la variable global a un objeto diferente, debe usar la palabra clave global nuevamente:

def change_global_variable():
    global global_variable
    global_variable = 'Bar'

Tenga en cuenta que después de escribir esta función, el código que realmente la cambia aún no se ha ejecutado:

>>> use_global_variable()
'Foo!!!'

Entonces, después de llamar a la función:

>>> change_global_variable()

Podemos ver que la variable global ha cambiado. El global_variablenombre ahora apunta a 'Bar':

>>> use_global_variable()
'Bar!!!'

Tenga en cuenta que "global" en Python no es verdaderamente global, solo es global al nivel del módulo. Por lo tanto, solo está disponible para funciones escritas en los módulos en los que es global. Las funciones recuerdan el módulo en el que están escritas, por lo que cuando se exportan a otros módulos, aún buscan en el módulo en el que fueron creadas para encontrar variables globales.

Variables locales con el mismo nombre.

Si crea una variable local con el mismo nombre, eclipsará una variable global:

def use_local_with_same_name_as_global():
    # bad name for a local variable, though.
    global_variable = 'Baz' 
    return global_variable + '!!!'

>>> use_local_with_same_name_as_global()
'Baz!!!'

Pero usar esa variable local mal nombrada no cambia la variable global:

>>> use_global_variable()
'Bar!!!'

Tenga en cuenta que debe evitar usar las variables locales con los mismos nombres que los globales, a menos que sepa exactamente lo que está haciendo y tenga una muy buena razón para hacerlo. Todavía no he encontrado tal razón.

Tenemos el mismo comportamiento en las clases.

Un seguimiento en el comentario pregunta:

¿Qué hacer si quiero crear una variable global dentro de una función dentro de una clase y quiero usar esa variable dentro de otra función dentro de otra clase?

Aquí demuestro que obtenemos el mismo comportamiento en los métodos que en las funciones regulares:

class Foo:
    def foo(self):
        global global_variable
        global_variable = 'Foo'

class Bar:
    def bar(self):
        return global_variable + '!!!'

Foo().foo()

Y ahora:

>>> Bar().bar()
'Foo!!!'

Pero sugeriría que, en lugar de usar variables globales, use atributos de clase, para evitar saturar el espacio de nombres del módulo. También tenga en cuenta que no usamos selfargumentos aquí; estos podrían ser métodos de clase (útiles si muta el atributo de clase del clsargumento habitual ) o métodos estáticos (no selfo cls).


Genial, pero ¿qué debo hacer si quiero crear una variable global dentro de una función dentro de una clase y quiero usar esa variable dentro de otra función dentro de otra clase? Un poco atrapado aquí
anonmanx

2
@anonmanx No sé por qué estás atascado, es el mismo comportamiento en un método que en una función normal. Pero actualizaré mi respuesta con tu comentario y un código de demostración, ¿de acuerdo?
Aaron Hall

1
@anonmanx ¿cómo es eso?
Aaron Hall

Ok, lo tengo. Entonces tendré que llamar explícitamente a esa función para usar esa variable global.
anonmanx

47

Además de las respuestas ya existentes y para hacer esto más confuso:

En Python, las variables a las que solo se hace referencia dentro de una función son implícitamente globales . Si a una variable se le asigna un nuevo valor en cualquier lugar dentro del cuerpo de la función, se supone que es un local . Si a una variable se le asigna un nuevo valor dentro de la función, la variable es implícitamente local y debe declararla explícitamente como 'global'.

Aunque un poco sorprendente al principio, un momento de consideración lo explica. Por un lado, requerir global para las variables asignadas proporciona una barra contra los efectos secundarios no deseados. Por otro lado, si se requiriera global para todas las referencias globales, estaría usando global todo el tiempo. Tendría que declarar como global cada referencia a una función incorporada o a un componente de un módulo importado. Este desorden derrotaría la utilidad de la declaración global para identificar los efectos secundarios.

Fuente: ¿Cuáles son las reglas para las variables locales y globales en Python? .


34

Con la ejecución paralela, las variables globales pueden causar resultados inesperados si no comprende lo que está sucediendo. Aquí hay un ejemplo del uso de una variable global dentro del multiprocesamiento. Podemos ver claramente que cada proceso funciona con su propia copia de la variable:

import multiprocessing
import os
import random
import sys
import time

def worker(new_value):
    old_value = get_value()
    set_value(random.randint(1, 99))
    print('pid=[{pid}] '
          'old_value=[{old_value:2}] '
          'new_value=[{new_value:2}] '
          'get_value=[{get_value:2}]'.format(
          pid=str(os.getpid()),
          old_value=old_value,
          new_value=new_value,
          get_value=get_value()))

def get_value():
    global global_variable
    return global_variable

def set_value(new_value):
    global global_variable
    global_variable = new_value

global_variable = -1

print('before set_value(), get_value() = [%s]' % get_value())
set_value(new_value=-2)
print('after  set_value(), get_value() = [%s]' % get_value())

processPool = multiprocessing.Pool(processes=5)
processPool.map(func=worker, iterable=range(15))

Salida:

before set_value(), get_value() = [-1]
after  set_value(), get_value() = [-2]
pid=[53970] old_value=[-2] new_value=[ 0] get_value=[23]
pid=[53971] old_value=[-2] new_value=[ 1] get_value=[42]
pid=[53970] old_value=[23] new_value=[ 4] get_value=[50]
pid=[53970] old_value=[50] new_value=[ 6] get_value=[14]
pid=[53971] old_value=[42] new_value=[ 5] get_value=[31]
pid=[53972] old_value=[-2] new_value=[ 2] get_value=[44]
pid=[53973] old_value=[-2] new_value=[ 3] get_value=[94]
pid=[53970] old_value=[14] new_value=[ 7] get_value=[21]
pid=[53971] old_value=[31] new_value=[ 8] get_value=[34]
pid=[53972] old_value=[44] new_value=[ 9] get_value=[59]
pid=[53973] old_value=[94] new_value=[10] get_value=[87]
pid=[53970] old_value=[21] new_value=[11] get_value=[21]
pid=[53971] old_value=[34] new_value=[12] get_value=[82]
pid=[53972] old_value=[59] new_value=[13] get_value=[ 4]
pid=[53973] old_value=[87] new_value=[14] get_value=[70]

25

Lo que estás diciendo es usar el método de esta manera:

globvar = 5

def f():
    var = globvar
    print(var)

f()  # Prints 5

Pero la mejor manera es usar la variable global de esta manera:

globavar = 5
def f():
    global globvar
    print(globvar)
f()   #prints 5

Ambos dan la misma salida.


25

Como resultado, la respuesta siempre es simple.

Aquí hay un pequeño módulo de muestra con una forma simple de mostrarlo en una maindefinición:

def five(enterAnumber,sumation):
    global helper
    helper  = enterAnumber + sumation

def isTheNumber():
    return helper

Aquí está cómo mostrarlo en una maindefinición:

import TestPy

def main():
    atest  = TestPy
    atest.five(5,8)
    print(atest.isTheNumber())

if __name__ == '__main__':
    main()

Este código simple funciona así, y se ejecutará. Espero que ayude.


1
gracias, soy nuevo en python, pero conozco un poco de java. Lo que dijiste funcionó para mí. y escribir global a <ENTER> dentro de la clase ... parece tener más sentido para mí que dentro de una función que escribe 'global a' ... Me doy cuenta de que no se puede decir global a = 4
barlop

2
Este es probablemente el truco de Python más simple pero muy útil para mí. Nombro este módulo global_varse inicializo los datos init_global_varsque se llaman en el script de inicio. Luego, simplemente creo un método de acceso para cada var global definida. ¡Espero poder votar esto varias veces! Gracias Peter!
swdev

1
¿Qué pasa si hay muchas variables globales y no quiero tener que enumerarlas una por una después de una declaración global?
jtlz2

23

Debe hacer referencia a la variable global en cada función que desee utilizar.

Como sigue:

var = "test"

def printGlobalText():
    global var #wWe are telling to explicitly use the global version
    var = "global from printGlobalText fun."
    print "var from printGlobalText: " + var

def printLocalText():
    #We are NOT telling to explicitly use the global version, so we are creating a local variable
    var = "local version from printLocalText fun"
    print "var from printLocalText: " + var

printGlobalText()
printLocalText()
"""
Output Result:
var from printGlobalText: global from printGlobalText fun.
var from printLocalText: local version from printLocalText
[Finished in 0.1s]
"""

3
'en cada función que desea usar' es sutilmente incorrecto, debería estar más cerca de: 'en cada función donde desea actualizar '
spazm

21

En realidad, no está almacenando el global en una variable local, solo está creando una referencia local al mismo objeto al que se refiere su referencia global original. Recuerde que casi todo en Python es un nombre que se refiere a un objeto, y nada se copia en la operación habitual.

Si no tuviera que especificar explícitamente cuándo un identificador debía referirse a un global predefinido, presumiblemente tendría que especificar explícitamente cuándo un identificador es una nueva variable local (por ejemplo, con algo como el comando 'var' visto en JavaScript). Dado que las variables locales son más comunes que las variables globales en cualquier sistema serio y no trivial, el sistema de Python tiene más sentido en la mayoría de los casos.

Usted podría tener un lenguaje que trataba de adivinar, utilizando una variable global si existía o crear una variable local si no lo hizo. Sin embargo, eso sería muy propenso a errores. Por ejemplo, importar otro módulo podría introducir inadvertidamente una variable global con ese nombre, cambiando el comportamiento de su programa.


17

Prueba esto:

def x1():
    global x
    x = 6

def x2():
    global x
    x = x+1
    print x

x = 5
x1()
x2()  # output --> 7


14

Siguiendo y como complemento, use un archivo para contener todas las variables globales, todas declaradas localmente y luego import as:

Archivo initval.py :

Stocksin = 300
Prices = []

Archivo getstocks.py :

import initval as iv

def getmystocks(): 
    iv.Stocksin = getstockcount()


def getmycharts():
    for ic in range(iv.Stocksin):

1
¿Cuál es la ventaja de mover las variables globales a otro archivo? ¿Es solo para agrupar las variables globales en un archivo pequeño? ¿Y por qué usar la declaración import ... as ...? ¿Por qué no solo import ...?
olibre

1
Ah ... finalmente entendí la ventaja: no es necesario usar la palabra clave global:-) => +1 :-) Edite su respuesta para aclarar estos interrogatorios que otras personas también pueden tener. Saludos
olibre

13

Escribir en elementos explícitos de una matriz global aparentemente no necesita la declaración global, aunque escribir en ella "al por mayor" sí tiene ese requisito:

import numpy as np

hostValue = 3.14159
hostArray = np.array([2., 3.])
hostMatrix = np.array([[1.0, 0.0],[ 0.0, 1.0]])

def func1():
    global hostValue    # mandatory, else local.
    hostValue = 2.0

def func2():
    global hostValue    # mandatory, else UnboundLocalError.
    hostValue += 1.0

def func3():
    global hostArray    # mandatory, else local.
    hostArray = np.array([14., 15.])

def func4():            # no need for globals
    hostArray[0] = 123.4

def func5():            # no need for globals
    hostArray[1] += 1.0

def func6():            # no need for globals
    hostMatrix[1][1] = 12.

def func7():            # no need for globals
    hostMatrix[0][0] += 0.33

func1()
print "After func1(), hostValue = ", hostValue
func2()
print "After func2(), hostValue = ", hostValue
func3()
print "After func3(), hostArray = ", hostArray
func4()
print "After func4(), hostArray = ", hostArray
func5()
print "After func5(), hostArray = ", hostArray
func6()
print "After func6(), hostMatrix = \n", hostMatrix
func7()
print "After func7(), hostMatrix = \n", hostMatrix

7

Estoy agregando esto ya que no lo he visto en ninguna de las otras respuestas y podría ser útil para alguien que lucha con algo similar. La globals()función devuelve un diccionario de símbolos global mutable donde puede "mágicamente" hacer que los datos estén disponibles para el resto de su código. Por ejemplo:

from pickle import load
def loaditem(name):
    with open(r"C:\pickle\file\location"+"\{}.dat".format(name), "rb") as openfile:
        globals()[name] = load(openfile)
    return True

y

from pickle import dump
def dumpfile(name):
    with open(name+".dat", "wb") as outfile:
        dump(globals()[name], outfile)
    return True

Simplemente le permitirá volcar / cargar variables fuera y dentro del espacio de nombres global. Súper conveniente, sin complicaciones, sin problemas. Estoy bastante seguro de que solo es Python 3.


3
globals()siempre devuelve globales disponibles en el contexto local, por lo que una mutación aquí puede no reflejarse en otro módulo.
Kiran Jonnalagadda

6

Consulte el espacio de nombres de clase donde desea que se muestre el cambio.

En este ejemplo, el corredor está usando max de la configuración del archivo. Quiero que mi prueba cambie el valor de max cuando el corredor la esté usando.

main / config.py

max = 15000

main / runner.py

from main import config
def check_threads():
    return max < thread_count 

tests / runner_test.py

from main import runner                # <----- 1. add file
from main.runner import check_threads
class RunnerTest(unittest):
   def test_threads(self):
       runner.max = 0                  # <----- 2. set global 
       check_threads()

1

Los globales están bien, excepto con multiprocesamiento

Los problemas globales relacionados con el multiprocesamiento en diferentes plataformas / entornos como Windows / Mac OS por un lado y Linux por el otro son problemáticos.

Te mostraré esto con un ejemplo simple que señala un problema que encontré hace algún tiempo.

Si quieres entender por qué las cosas son diferentes en Windows / MacOs y Linux, debes saber eso, el mecanismo predeterminado para comenzar un nuevo proceso en ...

  • Windows / MacOs es 'spawn'
  • Linux es 'fork'

Son diferentes en la asignación de memoria y la inicialización ... (pero no voy a esto aquí).

Echemos un vistazo al problema / ejemplo ...

import multiprocessing

counter = 0

def do(task_id):
    global counter
    counter +=1
    print(f'task {task_id}: counter = {counter}')

if __name__ == '__main__':

    pool = multiprocessing.Pool(processes=4)
    task_ids = list(range(4))
    pool.map(do, task_ids)

Ventanas

Si ejecuta esto en Windows (y supongo que también en MacOS), obtendrá el siguiente resultado ...

task 0: counter = 1
task 1: counter = 2
task 2: counter = 3
task 3: counter = 4

Linux

Si ejecuta esto en Linux, obtendrá lo siguiente en su lugar.

task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.