Usando variáveis ​​globais entre arquivos?

209

Estou um pouco confuso sobre como as variáveis ​​globais funcionam. Eu tenho um projeto grande, com cerca de 50 arquivos, e preciso definir variáveis ​​globais para todos esses arquivos.

O que fiz foi defini-los no meu main.pyarquivo de projetos , da seguinte maneira:

# ../myproject/main.py

# Define global myList
global myList
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

Eu estou tentando usar myListem subfile.py, como a seguir

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
    globals()["myList"].append("hey")

Por outro lado, tentei, mas também não funcionou

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

E por dentro subfile.pyeu tinha isso:

# ../myproject/subfile.py

# Import globfile
import globfile

# Save "hey" into myList
def stuff():
    globfile.myList.append("hey")

Mas, novamente, não funcionou. Como devo implementar isso? Entendo que não pode funcionar assim, quando os dois arquivos não se conhecem (o subarquivo não conhece main), mas não consigo pensar em como fazê-lo, sem usar io writing ou pickle, o que Eu não quero fazer

Martineau
fonte
Na verdade, sua segunda abordagem funciona muito bem para mim. main.py imprime corretamente "ei". Você pode ser mais específico sobre o que você me "não funcionou"?
Rodion19
@rodion: ciclos importadores - o código em tentativas de subarquivo para globfile de importação, que na sua própria volta importações corpo
jsbueno
1
NameError: name 'myList' is not definedfrom main.pylineprint(globfile.myList[0])

Respostas:

320

O problema é que você definido myLista partir main.py, mas subfile.pyprecisa usá-lo. Aqui está uma maneira limpa de resolver esse problema: mova todos os globais para um arquivo, eu chamo esse arquivo settings.py. Este arquivo é responsável por definir globais e inicializá-los:

# settings.py

def init():
    global myList
    myList = []

Em seguida, você subfilepode importar globais:

# subfile.py

import settings

def stuff():
    settings.myList.append('hey')

Observe que subfilenão chama init()- essa tarefa pertence a main.py:

# main.py

import settings
import subfile

settings.init()          # Call only once
subfile.stuff()         # Do stuff with global var
print settings.myList[0] # Check the result

Dessa forma, você alcança seu objetivo e evita inicializar variáveis ​​globais mais de uma vez.

Hai Vu
fonte
41
Eu gosto da abordagem geral, mas não de init()tudo. Os módulos são avaliados apenas na primeira vez que são importados, portanto, é perfeitamente bom inicializar essas variáveis ​​no corpo do módulo.
precisa
19
+1 Kirk: Eu concordo. No entanto, minha abordagem evita que outros módulos modifiquem globals.myList antes do início do programa principal.
Hai Vu
2
Você deve chamar algo diferente de global, que é um nome interno. PyLint dá o aviso: "Redefinindo 'globais' incorporados (redefinidos)"
twasbrillig 27/01
Obrigado. Alguma idéia de como remover os erros “Variável indefinida da importação” que aparecem no Eclipse PyDev usando essa estrutura de arquivo (ou seja, importando variáveis ​​globais do settings.py)? Eu tive que desativar o erro no PyDev , o que não é o ideal.
Franck Dernoncourt
@FranckDernoncourt Sinto muito, não uso o Eclipse, por isso sou ainda mais ignorante do que você.
Hai Vu
94

Veja o documento do Python sobre o compartilhamento de variáveis ​​globais entre módulos :

A maneira canônica de compartilhar informações entre módulos em um único programa é criar um módulo especial (geralmente chamado de config ou cfg).

config.py:

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

Importe o módulo de configuração em todos os módulos do seu aplicativo; o módulo fica disponível como um nome global.

main.py:

import config
print (config.x)

ou

from config import x
print (x)

Em geral, não use from modulename import * . Isso atrapalha o namespace do importador e torna muito mais difícil para os linters detectar nomes indefinidos.

Ogaga Uzoh
fonte
1
Lifesaver - apenas para esse link!
amigos estão dizendo sobre toonarmycaptain
4
Parece uma abordagem mais limpa do que a resposta aceita.
JoeyC
2
Observe que você não pode definir xusando from config import x, apenas usandoimport config
Yariv
1
Solução mais simples! Graças
user1297406
22

Você pode pensar nas variáveis ​​globais do Python como variáveis ​​de "módulo" - e, como tal, são muito mais úteis que as tradicionais "variáveis ​​globais" de C.

Uma variável global é realmente definida nos módulos __dict__e pode ser acessada de fora desse módulo como um atributo do módulo.

Então, no seu exemplo:

# ../myproject/main.py

# Define global myList
# global myList  - there is no "global" declaration at module level. Just inside
# function and methods
myList = []

# Imports
import subfile

# Do something
subfile.stuff()
print(myList[0])

E:

# ../myproject/subfile.py

# Save "hey" into myList
def stuff():
     # You have to make the module main available for the 
     # code here.
     # Placing the import inside the function body will
     # usually avoid import cycles - 
     # unless you happen to call this function from 
     # either main or subfile's body (i.e. not from inside a function or method)
     import main
     main.mylist.append("hey")
jsbueno
fonte
1
uau, normalmente seria de esperar que dois arquivos se importassem entrassem em um loop infinito.
precisa saber é o seguinte
2
ha À primeira vista, parece assim, não é? O que acontece no def stuff () é que a importação não é executada quando o arquivo é carregado .. apenas é executada quando a função stuff () é chamada. Então, começando com main, importamos o subarquivo e, em seguida, chamamos subfile.stuff (), que importa o main ... no loop, basta importar uma vez no main. Veja a nota no exemplo subfile.py sobre ciclos de importação.
John
11

Usando from your_file import * deve corrigir seus problemas. Ele define tudo para que esteja disponível globalmente (com exceção das variáveis ​​locais nas importações, é claro).

por exemplo:

##test.py:

from pytest import *

print hello_world

e:

##pytest.py

hello_world="hello world!"
IT Ninja
fonte
4
Exceto se você atribuir a uma tal variável
jsbueno
5
Pessoalmente, evito o uso import *a todo custo, para que as referências sejam explícitas (e não confusas). Além disso, quando você " *" usou todas as referências em algum módulo?
ThorSummoner 18/09/14
19
NÃO IMPORTA *. Suas variáveis ​​globais não permanecerão mais sincronizadas. Cada módulo recebe sua própria cópia. Alterar a variável em um arquivo não refletirá em outro. Também é avisado em docs.python.org/2/faq/…
Isa Hassen
8

A resposta Hai Vu funciona muito bem, apenas um comentário:

Caso você esteja usando o global em outro módulo e deseje configurá-lo dinamicamente, preste atenção para importar os outros módulos depois de definir as variáveis ​​globais, por exemplo:

# settings.py
def init(arg):
    global myList
    myList = []
    mylist.append(arg)


# subfile.py
import settings

def print():
    settings.myList[0]


# main.py
import settings
settings.init("1st")     # global init before used in other imported modules
                         # Or else they will be undefined

import subfile    
subfile.print()          # global usage
lastboy
fonte
4

Sua segunda tentativa funcionará perfeitamente e é realmente uma boa maneira de lidar com nomes de variáveis ​​que você deseja disponibilizar globalmente. Mas você tem um erro de nome na última linha. Aqui está como deve ser:

# ../myproject/main.py

# Import globfile    
import globfile

# Save myList into globfile
globfile.myList = []

# Import subfile
import subfile

# Do something
subfile.stuff()
print(globfile.myList[0])

Veja a última linha? myList é um atributo de globfile, não subarquivo. Isso funcionará como você deseja.

Mike

MikeHunter
fonte