Variáveis ​​globais da função Python?

272

Sei que devo evitar o uso de variáveis ​​globais em primeiro lugar devido a uma confusão como essa, mas se eu as usar, a seguinte é uma maneira válida de usá-las? (Estou tentando chamar a cópia global de uma variável criada em uma função 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()

O xque a segunda função usa tem o mesmo valor da cópia global xque func_ausa e modifica? Ao chamar as funções após a definição, a ordem importa?

Akshat Shekhar
fonte
1
tenha cuidado também para não assumir, apenas porque você tem uma variável atribuída em sua função que python tratará as referências antes da atribuição como tal. Até a primeira tarefa, se você usasse x, não seria a global ou a local. Você vai ter a exceção UnboundLocalError infame em seu rosto :)
osirisgothra

Respostas:

412

Se você deseja simplesmente acessar uma variável global, basta usar seu nome. No entanto, para alterar seu valor, você precisa usar a globalpalavra - chave.

Por exemplo

global someVar
someVar = 55

Isso mudaria o valor da variável global para 55. Caso contrário, apenas atribuiria 55 a uma variável local.

A ordem das listagens de definição de função não importa (supondo que elas não se refiram de alguma forma), a ordem em que são chamadas faz.

Levon
fonte
2
No código que eu dei, é func_B fazendo as coisas (1) para a cópia global de x (obtida de func_A), (2) para uma variável local x com o mesmo valor do resultado de func_A, ou (3) para uma variável local x sem valor e (aos olhos do compilador) nenhuma relação com "algum valor" ou x em func_A?
Akshat Shekhar
xem func_Bé uma variável local que recebe o seu valor a partir do valor de retorno da chamada para func_A- então eu acho que tornaria o seu (2)
Levon
ok, digamos que x fosse uma sequência aleatória de algum tipo gerada por func_A (ou seja, que func_A produzisse um x diferente cada vez que fosse executado.) A execução do programa, como escrita, faria func_b modificar um x diferente do que era originalmente produzido quando func_a era chamado? Se sim, como posso corrigi-lo?
Akshat Shekhar
1
Sim, se func_Aalterar a variável global durante cada execução e retornar func_Bpara uso, func_Bfuncionará com um valor alterado a cada vez. Não tenho certeza do seu "como consertar". Convém aceitar a resposta mais útil para sua pergunta atual / original e considere abrir uma pergunta diferente sobre o que parece ser uma pergunta de acompanhamento.
Levon
1
Na verdade, depende do que x é. Se x for imutável, o x em func_B permanecerá nele, porque é declarado localmente, mesmo que possua o mesmo valor. Isso se aplica a tuplas, ints ... Se é uma instância de uma lista, por exemplo, e você faz x.append("..."), é a variável global x que é alterada, porque a local refere-se à global.
Jadkik94
111

Dentro de um escopo Python, qualquer atribuição a uma variável ainda não declarada nesse escopo cria uma nova variável local, a menos que essa variável seja declarada anteriormente na função como se referindo a uma variável de escopo global com a palavra-chave global.

Vejamos uma versão modificada do seu pseudocódigo para ver o que acontece:

# 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 fato, você pode reescrever tudo func_Bcom a variável nomeada x_locale ela funcionaria de forma idêntica.

A ordem importa apenas na ordem em que suas funções executam operações que alteram o valor do x global. Assim, em nosso exemplo, a ordem não importa, desde as func_Bchamadas func_A. Neste exemplo, a ordem 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'.

Observe que globalé necessário apenas para modificar objetos globais. Você ainda pode acessá-los de dentro de uma função sem declarar global. Assim, temos:

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.

Observe a diferença entre create_locallye access_only- access_onlyestá acessando o x global, apesar de não chamar global, e mesmo que create_locallynão use global, ele cria uma cópia local, pois está atribuindo um valor.

A confusão aqui é por que você não deve usar variáveis ​​globais.

jdotjdot
fonte
2
Eu não acho que isso seja muito confuso na prática, você só precisa entender as regras de escopo do python .
Casey Kuball
20

Como outros observaram, você precisa declarar uma variável globalem uma função quando desejar que essa função possa modificar a variável global. Se você deseja apenas acessá-lo, não precisa global.

Para entrar um pouco mais detalhadamente, o que significa "modificar" é o seguinte: se você deseja vincular novamente o nome global para que ele aponte para um objeto diferente, o nome deve ser declarado globalna função.

Muitas operações que modificam (modificam) um objeto não religam o nome global para apontar para um objeto diferente e, portanto, todas são válidas sem declarar o nome globalna função.

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
kindall
fonte
8

Aqui está um caso que me chamou a atenção, usando um global como valor padrão de um 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

Eu esperava que o parâmetro tivesse um valor de 42. Surpresa. O Python 2.7 avaliou o valor de globVar quando analisou pela primeira vez a função func. Alterar o valor de globVar não afetou o valor padrão atribuído ao parâmetro. Atrasar a avaliação, como a seguir, funcionou como eu precisava.

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

Ou, se você quer estar seguro,

def func(param = None)):
    if param == None:
        param = globVar
    print 'param =', param, 'globVar =', globVar  # display values
SoloPilot
fonte
Isso me lembrou o problema de atribuir uma lista vazia como valor padrão . E, como no exemplo, use ispara verificar se há algo None, em vez da comparação normal ==.
berna1111 4/03
6

Você pode acessar diretamente uma variável global dentro de uma função. Se você deseja alterar o valor dessa variável global, use "global variable_name". Veja o seguinte exemplo:

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

De um modo geral, essa não é uma boa prática de programação. Ao quebrar a lógica do espaço para nome, o código pode se tornar difícil de entender e depurar.

Noisy_Botnet
fonte
2

Você deve usar a globaldeclaração quando desejar alterar o valor atribuído a uma variável global.

Você não precisa ler de uma variável global. Observe que a chamada de um método para um objeto (mesmo que ele altere os dados nesse objeto) não altera o valor da variável que contém esse objeto (ausência de mágica reflexiva).

Marcin
fonte
2
Esta redação é lamentável. No Python, o valor atribuído a uma variável é uma referência, portanto é tecnicamente correto (e não tenho dúvida de que você quis dizer isso), mas muitos leitores podem interpretar "alterar o valor" como "alterar o objeto", o que não é o caso - xs.append(xs.pop(0))funciona muito bem sem global xs.
@delnan Minha resposta é cuidadosamente formulada, mas vou esclarecer.
Marcin