Usando variáveis ​​globais em uma função


3115

Como posso criar ou usar uma variável global em uma função?

Se eu criar uma variável global em uma função, como posso usar essa variável global em outra função? Preciso armazenar a variável global em uma variável local da função que precisa de seu acesso?

Respostas:


4247

Você pode usar uma variável global em outras funções, declarando-a como globalem cada função que lhe atribui:

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

Imagino que a razão disso é que, como as variáveis ​​globais são tão perigosas, o Python quer ter certeza de que você realmente sabe o que está brincando ao exigir explicitamente a globalpalavra - chave.

Veja outras respostas se desejar compartilhar uma variável global entre módulos.


838
É um exagero extremo referir-se aos globais como "tão perigoso". Globais estão perfeitamente bem em todas as línguas que já existiram e sempre existirão. Eles têm o seu lugar. O que você deveria ter dito é que eles podem causar problemas se você não souber como programar.
Anthony

207
Eu acho que eles são bastante perigosos. No entanto, no python, as variáveis ​​"globais" são na verdade no nível do módulo, o que resolve muitos problemas.
Fábio Santos

246
Não concordo que o motivo pelo qual o Python exija a globalpalavra-chave seja porque os globais são perigosos. Pelo contrário, é porque o idioma não exige que você declare explicitamente variáveis ​​e assume automaticamente que uma variável que você atribui tem escopo de função, a menos que você diga o contrário. A globalpalavra-chave é o meio fornecido para dizer o contrário.
Nate CK

7
@avgvstvs: E se você estiver implementando o mesmo programa sem globais, ainda terá o mesmo número de caminhos de código. O argumento que você fez não é contra os globais.
Lightness Races em órbita

13
@LightnessRacesinOrbit Eu não estou entendendo o seu ponto. Se você remover uma variável global, removerá o fator complicador, já que funções arbitrárias não poderão mais alterar o estado do programa , em vários pontos da execução - alterando a execução de uma maneira que seria imperceptível para outras funções dependentes dessa variável. Você já não tem que manter o controle de: "Será que f2()estado mudança agora f3()poderia fazer algo inesperado As funções podem agora operar agnóstico para o estado programa externo?.
AVGVSTVS

775

Se estou entendendo sua situação corretamente, o que você está vendo é o resultado de como o Python lida com namespaces locais (funções) e globais (módulos).

Digamos que você tenha um módulo como este:

# sample.py
myGlobal = 5

def func1():
    myGlobal = 42

def func2():
    print myGlobal

func1()
func2()

Você pode esperar que isso imprima 42, mas em vez disso imprime 5. Como já foi mencionado, se você adicionar uma globaldeclaração ' ' a func1(), func2()imprimirá 42.

def func1():
    global myGlobal
    myGlobal = 42

O que está acontecendo aqui é que o Python assume que qualquer nome atribuído , em qualquer lugar de uma função, é local para essa função, a menos que seja explicitamente dito o contrário. Se estiver apenas lendo um nome e o nome não existir localmente, ele tentará procurar o nome em qualquer escopo que contenha (por exemplo, o escopo global do módulo).

Quando você atribui 42 ao nome myGlobal, o Python cria uma variável local que oculta a variável global com o mesmo nome. Esse local sai do escopo e é coletado como lixo quando func1()retorna; enquanto isso, func2()nunca poderá ver nada além do nome global (não modificado). Observe que essa decisão de namespace ocorre no tempo de compilação, não no tempo de execução - se você lesse o valor de myGlobalinside func1()antes de atribuir a ele, obteria um UnboundLocalError, porque o Python já decidiu que deve ser uma variável local, mas ainda não teve nenhum valor associado a ele. Mas, usando a globalinstrução ' ', você diz ao Python que ele deve procurar o nome em outro lugar, em vez de atribuí-lo localmente.

(Acredito que esse comportamento se originou amplamente de uma otimização de namespaces locais - sem esse comportamento, a VM do Python precisaria executar pelo menos três pesquisas de nome cada vez que um novo nome fosse atribuído dentro de uma função (para garantir que o nome não ' já existe no nível do módulo / interno), o que desaceleraria significativamente uma operação muito comum.)


Você mencionou que a decisão do namespace acontece no momento da compilação , não acho que seja verdade. pelo que aprendi, a compilação do python verifica apenas se há erro de sintaxe, não erro de nome, tente este exemplo def A (): x + = 1 , se você não executá-lo, ele não fornecerá UnboundLocalError , verifique obrigado
watashiSHUN

1
É comum usar uma letra maiúscula para variáveis ​​globais comoMyGlobal = 5
Vassilis

3
@watashiSHUN: A decisão namespace não acontecer em tempo de compilação. Decidir que xé local é diferente de verificar no tempo de execução se o nome do local foi associado a um valor antes de ser usado pela primeira vez.
precisa

9
@Vassilis: É comum para maiúsculas todas as letras: MY_GLOBAL = 5. Veja o Guia de Estilo para Código Python .
precisa

223

Você pode explorar a noção de namespaces . No Python, o módulo é o local natural para dados globais :

Cada módulo possui sua própria tabela de símbolos privada, que é usada como tabela de símbolos global por todas as funções definidas no módulo. Assim, o autor de um módulo pode usar variáveis ​​globais no módulo sem se preocupar com conflitos acidentais com as variáveis ​​globais de um usuário. Por outro lado, se você souber o que está fazendo, poderá tocar nas variáveis ​​globais de um módulo com a mesma notação usada para se referir a suas funções modname.itemname.

Um uso específico de global-in-a-module é descrito aqui - Como faço para compartilhar variáveis ​​globais entre módulos? , e para completar, o conteúdo é compartilhado aqui:

A maneira canônica de compartilhar informações entre módulos em um único programa é criar um módulo de configuração especial (geralmente chamado de config ou cfg ). Basta importar o módulo de configuração em todos os módulos do seu aplicativo; o módulo fica disponível como um nome global. Como há apenas uma instância de cada módulo, quaisquer alterações feitas no objeto do módulo são refletidas em todos os lugares. Por exemplo:

Arquivo: config.py

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

Arquivo: mod.py

import config
config.x = 1

Arquivo: main.py

import config
import mod
print config.x

1
por uma razão que eu não gosto, config.x posso me livrar disso? Eu vim com x = lambda: config.xe então tenho o novo valor em x(). por alguma razão, ter a = config.xnão faz o truque para mim.
vladosaurus

3
@vladosaurus from config import xresolve isso?
perfil completo de jhylands

93

O Python usa uma heurística simples para decidir de qual escopo deve carregar uma variável, entre local e global. Se um nome de variável aparecer no lado esquerdo de uma atribuição, mas não for declarado global, será considerado local. Se ele não aparecer no lado esquerdo de uma atribuição, será considerado 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        
>>> 

Veja como baz, que aparece no lado esquerdo de uma tarefa em foo(), é a única LOAD_FASTvariável.


12
A heurística procura operações de ligação . A atribuição é uma dessas operações, importando outra. Mas o destino de um forloop e o nome after asin withe as exceptinstruções também estão vinculados.
Martijn Pieters

@ MartijnPieters Para o nome depois asde uma exceptcláusula, isso não era óbvio para mim. Mas é excluído automaticamente para economizar memória.
Robert

1
@ Robert: não para economizar memória, mas para evitar criar uma referência circular, o que pode levar a vazamentos de memória. Isso ocorre porque uma exceção faz referência a um retorno e o retorno faz referência a todos os namespaces locais e globais ao longo de toda a pilha de chamadas, incluindo o as ...destino no manipulador de exceções.
Martijn Pieters

62

Se você quiser se referir a uma variável global em uma função, poderá usar a palavra-chave global para declarar quais variáveis ​​são globais. Você não precisa usá-lo em todos os casos (como alguém aqui afirma incorretamente) - se o nome referenciado em uma expressão não puder ser encontrado no escopo ou nos escopos locais nas funções em que essa função é definida, ela será pesquisada entre os globais variáveis.

No entanto, se você atribuir a uma nova variável não declarada como global na função, ela será declarada implicitamente como local e poderá ofuscar qualquer variável global existente com o mesmo nome.

Além disso, variáveis ​​globais são úteis, ao contrário de alguns fanáticos por OOP que afirmam o contrário - especialmente para scripts menores, onde o OOP é um exagero.


Absolutamente re. fanáticos. A maioria dos usuários de Python o utiliza para criar scripts e criar pequenas funções para separar pequenos pedaços de código.
Paul Uszak 22/09/19

51

Se eu criar uma variável global em uma função, como posso usar essa variável em outra função?

Podemos criar um global com a seguinte função:

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' 

Escrever uma função não executa seu código. Então chamamos a create_global_variablefunção:

>>> create_global_variable()

Usando globais sem modificação

Você pode apenas usá-lo, desde que não espere alterar para qual objeto ele aponta:

Por exemplo,

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

e agora podemos usar a variável global:

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

Modificação da variável global de dentro de uma função

Para apontar a variável global para um objeto diferente, você deve usar a palavra-chave global novamente:

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

Observe que, após escrever esta função, o código que realmente a altera ainda não foi executado:

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

Então, depois de chamar a função:

>>> change_global_variable()

podemos ver que a variável global foi alterada. O global_variablenome agora aponta para 'Bar':

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

Observe que "global" no Python não é verdadeiramente global - é apenas global no nível do módulo. Portanto, ele está disponível apenas para funções escritas nos módulos em que é global. As funções lembram o módulo em que foram gravadas; portanto, quando são exportadas para outros módulos, elas ainda procuram no módulo em que foram criadas para encontrar variáveis ​​globais.

Variáveis ​​locais com o mesmo nome

Se você criar uma variável local com o mesmo nome, ela irá ofuscar uma variável 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!!!'

Mas o uso dessa variável local com nome incorreto não altera a variável global:

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

Observe que você deve evitar o uso de variáveis ​​locais com os mesmos nomes de globais, a menos que saiba exatamente o que está fazendo e tenha um bom motivo para fazê-lo. Ainda não encontrei esse motivo.

Temos o mesmo comportamento nas aulas

Um comentário a seguir pergunta:

o que fazer se eu quiser criar uma variável global dentro de uma função dentro de uma classe e desejar usar essa variável dentro de outra função dentro de outra classe?

Aqui, demonstro que temos o mesmo comportamento nos métodos que fazemos nas funções regulares:

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

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

Foo().foo()

E agora:

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

Mas eu sugiro que, em vez de usar variáveis ​​globais, você use atributos de classe, para evitar sobrecarregar o espaço para nome do módulo. Observe também que não usamos selfargumentos aqui - esses podem ser métodos de classe (úteis se você alterar o atributo de classe do clsargumento usual ) ou métodos estáticos (não selfou cls).


Legal, mas o que fazer se eu quiser criar uma variável global dentro de uma função dentro de uma classe e quiser usar essa variável dentro de outra função dentro de outra classe?
Meio

2
@anonmanx Eu não sei por que você está preso, é o mesmo comportamento em um método e em uma função regular. Mas vou atualizar minha resposta com sua observação e algum código de demonstração, ok?
Aaron Hall

1
@anonmanx como é isso?
Aaron Hall

tudo bem, entendi. Então terei que chamar explicitamente essa função para usar essa variável global.
anonmanx 19/01

47

Além das respostas já existentes e para tornar isso mais confuso:

No Python, variáveis ​​referenciadas apenas dentro de uma função são implicitamente globais . Se uma variável receber um novo valor em qualquer parte do corpo da função, será considerado um local . Se alguma vez for atribuído a uma variável um novo valor dentro da função, ela é implicitamente local e você precisará declará-la explicitamente como 'global'.

Embora um pouco surpreendente no começo, um momento de consideração explica isso. Por um lado, exigir global para variáveis ​​atribuídas fornece uma barreira contra efeitos colaterais indesejados. Por outro lado, se global fosse necessário para todas as referências globais, você usaria global o tempo todo. Você teria que declarar como global todas as referências a uma função interna ou a um componente de um módulo importado. Essa confusão derrotaria a utilidade da declaração global para identificar efeitos colaterais.

Fonte: Quais são as regras para variáveis ​​locais e globais no Python? .


34

Com a execução paralela, variáveis ​​globais podem causar resultados inesperados se você não entender o que está acontecendo. Aqui está um exemplo de uso de uma variável global no multiprocessamento. Podemos ver claramente que cada processo trabalha com sua própria cópia da variável:

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))

Resultado:

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

O que você está dizendo é usar o método como este:

globvar = 5

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

f()  # Prints 5

Mas a melhor maneira é usar a variável global como esta:

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

Ambos dão a mesma saída.


25

Como se vê, a resposta é sempre simples.

Aqui está um pequeno módulo de amostra com uma maneira simples de mostrá-lo em uma maindefinição:

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

def isTheNumber():
    return helper

Aqui está como mostrá-lo em uma maindefinição:

import TestPy

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

if __name__ == '__main__':
    main()

Esse código simples funciona assim e é executado. Espero que ajude.


1
obrigado, sou novo em python, mas conheço um pouco de java. o que você disse funcionou para mim. e escrever um global <ENTER> dentro da classe .. parece fazer mais sentido para mim do que dentro de uma função que escreve 'global a'. Percebo que você não pode dizer global a = 4
barlop

2
Este é provavelmente o truque python mais simples e muito útil para mim. Nomeio este módulo global_varse inicializo os dados init_global_vars, que estão sendo chamados no script de inicialização. Então, simplesmente crio o método de acessador para cada var global definida. Espero poder votar isso várias vezes! Obrigado Peter!
swdev

1
E se houver muitas variáveis ​​globais e eu não desejar listá-las uma a uma após uma declaração global?
Jtlz2

23

Você precisa fazer referência à variável global em todas as funções que deseja usar.

Do seguinte modo:

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
'em todas as funções que você deseja usar' está sutilmente incorreto, deve estar mais próximo de: 'em todas as funções em que você deseja atualizar '
spazm

21

Na verdade, você não está armazenando o global em uma variável local, apenas criando uma referência local para o mesmo objeto ao qual sua referência global original se refere. Lembre-se de que praticamente tudo no Python é um nome referente a um objeto, e nada é copiado na operação usual.

Se você não precisou especificar explicitamente quando um identificador deveria se referir a um global predefinido, presumivelmente teria que especificar explicitamente quando um identificador é uma nova variável local (por exemplo, com algo como o comando 'var' visto em JavaScript). Como as variáveis ​​locais são mais comuns que as globais em qualquer sistema sério e não trivial, o sistema do Python faz mais sentido na maioria dos casos.

Você poderia ter um idioma que tentasse adivinhar, usando uma variável global se ela existisse ou criando uma variável local se não existisse. No entanto, isso seria muito propenso a erros. Por exemplo, a importação de outro módulo pode inadvertidamente introduzir uma variável global com esse nome, alterando o comportamento do seu programa.


17

Tente o seguinte:

def x1():
    global x
    x = 6

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

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


14

Após e como complemento, use um arquivo para conter todas as variáveis ​​globais, todas declaradas localmente e, em seguida, import as :

Arquivo initval.py :

Stocksin = 300
Prices = []

Arquivo getstocks.py :

import initval as iv

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


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

1
Qual é a vantagem de mover as variáveis ​​globais para outro arquivo? É apenas para agrupar as variáveis ​​globais em um pequeno arquivo? E por que usar a declaração import ... as ...? Por que não apenas import ...?
Olibre 23/05

1
Ah ... finalmente entendi a vantagem: Não há necessidade de usar a palavra-chave global:-) => +1 :-) Por favor, edite sua resposta para esclarecer esses interrogatórios que outras pessoas também podem ter. Cheers
olibre

13

A gravação em elementos explícitos de uma matriz global aparentemente não precisa da declaração global, embora a gravação em "atacado" tenha esse 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

Estou adicionando isso porque não o vi em nenhuma das outras respostas e pode ser útil para alguém que está enfrentando algo semelhante. A globals()função retorna um dicionário de símbolos globais mutável, no qual você pode "magicamente" disponibilizar dados para o restante do seu código. Por exemplo:

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

e

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

Apenas permitirá que você faça o dump / carregue variáveis ​​fora e dentro do espaço de nomes global. Super conveniente, sem confusão, sem problemas. Certamente é apenas o Python 3.


3
globals()sempre retorna globais disponíveis no contexto local; portanto, uma mutação aqui pode não refletir em outro módulo.
Kiran Jonnalagadda

6

Faça referência ao namespace da classe em que deseja que a alteração seja exibida.

Neste exemplo, o runner está usando max na configuração do arquivo. Quero que meu teste altere o valor de max quando o corredor estiver 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

Globais estão bem - Exceto no Multiprocessamento

Globais em conexão com o multiprocessamento em diferentes plataformas / ambientes, como Windows / Mac OS, por um lado, e Linux, por outro, são problemáticos.

Vou mostrar isso com um exemplo simples, apontando um problema com o qual me deparo há algum tempo atrás.

Se você quer entender, por que as coisas são diferentes no Windows / MacOs e Linux, você precisa saber disso, o mecanismo padrão para iniciar um novo processo no ...

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

Eles são diferentes na alocação de memória, uma inicialização ... (mas eu não entendo isso aqui).

Vamos dar uma olhada no problema / exemplo ...

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)

janelas

Se você executar isso no Windows (e suponho também no MacOS), obterá a seguinte saída ...

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

Linux

Se você executar isso no Linux, obterá o seguinte.

task 0: counter = 1
task 1: counter = 1
task 2: counter = 1
task 3: counter = 1
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.