Variables globales de la función Python?

272

Sé que debería evitar el uso de variables globales en primer lugar debido a una confusión como esta, pero si tuviera que usarlas, ¿es la siguiente forma válida de usarlas? (Estoy tratando de llamar a la copia global de una variable creada en una función separada).

x = "somevalue"

def func_A ():
   global x
   # Do things to x
   return x

def func_B():
   x = func_A()
   # Do things
   return x

func_A()
func_B()

¿El xque usa la segunda función tiene el mismo valor de la copia global xque func_ausa y modifica? Al llamar a las funciones después de la definición, ¿importa el orden?

Akshat Shekhar
fuente
1
tenga cuidado también de no suponer solo porque tiene una variable asignada en su función que python tratará las referencias antes de la asignación como tales. Hasta la primera asignación, si usó x, no sería la global o la local. Obtendrá la infame excepción UnboundLocalError en su cara :)
osirisgothra

Respuestas:

412

Si desea acceder simplemente a una variable global, simplemente use su nombre. Sin embargo, para cambiar su valor, debe usar la globalpalabra clave.

P.ej

global someVar
someVar = 55

Esto cambiaría el valor de la variable global a 55. De lo contrario, simplemente asignaría 55 a una variable local.

El orden de las listas de definición de funciones no importa (suponiendo que no se refieran entre sí de alguna manera), sí lo hace el orden en que se llaman.

Levon
fuente
2
En el código que di, es func_B haciendo cosas (1) a la copia global de x (como se obtiene de func_A), (2) a una variable local x con el mismo valor del resultado de func_A, o (3) a una variable local x sin valor y (a los ojos del compilador) sin relación con "algún valor" o la x en func_A?
Akshat Shekhar
xin func_Bes una variable local que obtiene su valor del valor de retorno de la llamada a func_A- así que supongo que eso lo convertiría en su (2)
Levon
ok, digamos que x era una secuencia aleatoria de algún tipo generada por func_A (es decir, que func_A producía una x diferente cada vez que se ejecutaba). Al ejecutar el programa tal como está escrito, func_b modificaría una x diferente de la que se produjo originalmente cuando func_a ¿llamado? Si es así, ¿cómo puedo solucionarlo?
Akshat Shekhar
1
Sí, si func_Acambia la variable global durante cada ejecución y la vuelve func_Ba usar, func_Bfuncionará con un valor modificado cada vez. No estoy seguro acerca de su "cómo solucionarlo". Es posible que desee aceptar la respuesta más útil a su pregunta actual / original y luego considerar abrir una pregunta diferente sobre lo que parece una pregunta de seguimiento.
Levon
1
En realidad depende de qué es x. Si x es inmutable, entonces la x en func_B permanecerá en ella, porque se declara localmente incluso si tienen el mismo valor. Esto se aplica a tuplas, ints ... Si es una instancia de una lista, por ejemplo, y lo hace x.append("..."), es la variable global x la que cambia, porque la local hace referencia a la global.
jadkik94
111

Dentro de un alcance de Python, cualquier asignación a una variable que aún no se haya declarado dentro de ese alcance crea una nueva variable local a menos que dicha variable se declare anteriormente en la función como una referencia a una variable de ámbito global con la palabra clave global.

Veamos una versión modificada de su pseudocódigo para ver qué sucede:

# Here, we're creating a variable 'x', in the __main__ scope.
x = 'None!'

def func_A():
  # The below declaration lets the function know that we
  #  mean the global 'x' when we refer to that variable, not
  #  any local one

  global x
  x = 'A'
  return x

def func_B():
  # Here, we are somewhat mislead.  We're actually involving two different
  #  variables named 'x'.  One is local to func_B, the other is global.

  # By calling func_A(), we do two things: we're reassigning the value
  #  of the GLOBAL x as part of func_A, and then taking that same value
  #  since it's returned by func_A, and assigning it to a LOCAL variable
  #  named 'x'.     
  x = func_A() # look at this as: x_local = func_A()

  # Here, we're assigning the value of 'B' to the LOCAL x.
  x = 'B' # look at this as: x_local = 'B'

  return x # look at this as: return x_local

De hecho, podría reescribir todo func_Bcon la variable nombrada x_localy funcionaría de manera idéntica.

El orden solo importa en la medida en que sus funciones realizan operaciones que cambian el valor de la x global. Por lo tanto, en nuestro ejemplo, el orden no importa, ya que las func_Bllamadas func_A. En este ejemplo, el orden sí importa:

def a():
  global foo
  foo = 'A'

def b():
  global foo
  foo = 'B'

b()
a()
print foo
# prints 'A' because a() was the last function to modify 'foo'.

Tenga en cuenta que globalsolo es necesario para modificar objetos globales. Aún puede acceder a ellos desde una función sin declararlos global. Por lo tanto, tenemos:

x = 5

def access_only():
  return x
  # This returns whatever the global value of 'x' is

def modify():
  global x
  x = 'modified'
  return x
  # This function makes the global 'x' equal to 'modified', and then returns that value

def create_locally():
  x = 'local!'
  return x
  # This function creates a new local variable named 'x', and sets it as 'local',
  #  and returns that.  The global 'x' is untouched.

Tenga en cuenta que la diferencia entre create_locallyy access_only- access_onlyes acceder a la x global a pesar de no llamar global, y aunque create_locallyno usa globalninguno, crea una copia local ya que está asignando un valor.

La confusión aquí es por qué no debe usar variables globales.

jdotjdot
fuente
2
No creo que esto sea muy confuso en la práctica, solo tienes que entender las reglas de alcance de Python .
Casey Kuball
20

Como otros han señalado, debe declarar una variable globalen una función cuando desea que esa función pueda modificar la variable global. Si solo quieres acceder a él, entonces no lo necesitas global.

Para entrar en un poco más de detalle sobre eso, lo que significa "modificar" es esto: si desea volver a vincular el nombre global para que apunte a un objeto diferente, el nombre debe declararse globalen la función.

Muchas operaciones que modifican (mutan) un objeto no vuelven a vincular el nombre global para apuntar a un objeto diferente, por lo que todas son válidas sin declarar el nombre globalen la función.

d = {}
l = []
o = type("object", (object,), {})()

def valid():     # these are all valid without declaring any names global!
   d[0] = 1      # changes what's in d, but d still points to the same object
   d[0] += 1     # ditto
   d.clear()     # ditto! d is now empty but it`s still the same object!
   l.append(0)   # l is still the same list but has an additional member
   o.test = 1    # creating new attribute on o, but o is still the same object
un poco
fuente
8

Aquí hay un caso que me sorprendió, usando un valor global como valor predeterminado de un parámetro.

globVar = None    # initialize value of global variable

def func(param = globVar):   # use globVar as default value for param
    print 'param =', param, 'globVar =', globVar  # display values

def test():
    global globVar
    globVar = 42  # change value of global
    func()

test()
=========
output: param = None, globVar = 42

Esperaba que param tuviera un valor de 42. Sorpresa. Python 2.7 evaluó el valor de globVar cuando analizó por primera vez la función func. Cambiar el valor de globVar no afectó el valor predeterminado asignado a param. Retrasar la evaluación, como en el siguiente, funcionó como lo necesitaba.

def func(param = eval('globVar')):       # this seems to work
    print 'param =', param, 'globVar =', globVar  # display values

O, si quieres estar a salvo,

def func(param = None)):
    if param == None:
        param = globVar
    print 'param =', param, 'globVar =', globVar  # display values
SoloPilot
fuente
Eso me recordó el problema de asignar una lista vacía como valor predeterminado . Y, como en el ejemplo, use ispara verificar si algo es None, en lugar de la comparación normal ==.
berna1111
6

Puede acceder directamente a una variable global dentro de una función. Si desea cambiar el valor de esa variable global, use "global variable_name". Vea el siguiente ejemplo:

var = 1
def global_var_change():
      global var
      var = "value changed"
global_var_change() #call the function for changes
print var

En términos generales, esta no es una buena práctica de programación. Al romper la lógica del espacio de nombres, el código puede volverse difícil de entender y depurar.

Noisy_Botnet
fuente
2

Debe usar la globaldeclaración cuando desee alterar el valor asignado a una variable global.

No lo necesita para leer desde una variable global. Tenga en cuenta que llamar a un método en un objeto (incluso si altera los datos dentro de ese objeto) no altera el valor de la variable que contiene ese objeto (ausencia de magia reflexiva).

Marcin
fuente
2
Esta redacción es desafortunada. En Python, el valor asignado a una variable es una referencia, por lo que es técnicamente correcto (y no tengo dudas de que lo dices en serio), pero muchos lectores pueden interpretar "alterar el valor" como "mutar el objeto", que no es El caso - xs.append(xs.pop(0))funciona bien sin global xs.
@delnan Mi respuesta está cuidadosamente redactada, pero aclararé.
Marcin