Eu me deparei com uma espécie de parede importando módulos em um script Python. Farei o meu melhor para descrever o erro, por que o encontrei e por que estou vinculando essa abordagem específica para resolver meu problema (que descreverei em um segundo):
Vamos supor que eu tenha um módulo no qual defini algumas funções / classes de utilitários, que se referem a entidades definidas no namespace para o qual esse módulo auxiliar será importado (seja "a" essa entidade):
Módulo 1:
def f():
print a
E então eu tenho o programa principal, onde "a" é definido, para o qual desejo importar esses utilitários:
import module1
a=3
module1.f()
Executar o programa irá desencadear o seguinte erro:
Traceback (most recent call last):
File "Z:\Python\main.py", line 10, in <module>
module1.f()
File "Z:\Python\module1.py", line 3, in f
print a
NameError: global name 'a' is not defined
Perguntas semelhantes foram feitas no passado (dois dias atrás, d'uh) e várias soluções foram sugeridas, no entanto, eu realmente não acho que elas atendam aos meus requisitos. Este é meu contexto particular:
Estou tentando fazer um programa Python que se conecta a um servidor de banco de dados MySQL e exibe / modifica dados com uma GUI. Para fins de limpeza, defini o grupo de funções auxiliares / utilitárias relacionadas ao MySQL em um arquivo separado. No entanto, todos eles têm uma variável comum, que eu defini originalmente dentro do módulo de utilitários, e que é o objeto cursor do módulo MySQLdb. Mais tarde, percebi que o objeto cursor (que é usado para se comunicar com o servidor db) deve ser definido no módulo principal, de forma que tanto o módulo principal quanto qualquer coisa importada para ele possam acessar esse objeto.
O resultado final seria algo como este:
utilities_module.py:
def utility_1(args):
code which references a variable named "cur"
def utility_n(args):
etcetera
E meu módulo principal:
program.py:
import MySQLdb, Tkinter
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
E então, assim que tento chamar qualquer uma das funções de utilitários, ele aciona o erro "nome global não definido" mencionado anteriormente.
Uma sugestão particular era ter uma instrução "from program import cur" no arquivo de utilitários, como este:
utilities_module.py:
from program import cur
#rest of function definitions
program.py:
import Tkinter, MySQLdb
db=MySQLdb.connect(#blahblah) ; cur=db.cursor() #cur is defined!
from utilities_module import *
Mas isso é importação cíclica ou algo parecido e, no final das contas, também trava. Então, minha pergunta é:
Como diabos posso tornar o objeto "cur", definido no módulo principal, visível para as funções auxiliares que são importadas para ele?
Obrigado pelo seu tempo e minhas sinceras desculpas se a solução foi postada em outro lugar. Simplesmente não consigo encontrar a resposta sozinho e não tenho mais truques em meu livro.
fetch_all
iterar por meio de duas listas em vez disso , ou apenas para que você possa ter dois threads / greenlets / callback-chains / qualquer outro usando o banco de dados sem conflitos).db
(ecur
, se você insistir) em um módulo separado que tantoprogram
eutilities_module
importá-lo a partir. Dessa forma, você não obtém dependências circulares (importar programa de módulos que o programa importa) e a confusão que vem com eles.Respostas:
Globais em Python são globais para um módulo , não em todos os módulos. (Muitas pessoas ficam confusas com isso, porque em, digamos, C, um global é o mesmo em todos os arquivos de implementação, a menos que você o faça explicitamente
static
.)Existem diferentes maneiras de resolver isso, dependendo do seu caso de uso real.
Antes mesmo de trilhar esse caminho, pergunte-se se isso realmente precisa ser global. Talvez você realmente queira uma classe, com
f
um método de instância, em vez de apenas uma função livre? Então você poderia fazer algo assim:Se você realmente deseja um global, mas ele está lá apenas para ser usado por
module1
, defina-o nesse módulo.Por outro lado, se
a
for compartilhado por vários módulos, coloque-o em outro lugar e faça com que todos importem:… E, em module1.py:
Não use uma
from
importação a menos que a variável pretenda ser uma constante.from shared_stuff import a
criaria uma novaa
variável inicializada com qualquershared_stuff.a
referência no momento da importação, e essa novaa
variável não seria afetada pelas atribuições ashared_stuff.a
.Ou, no caso raro de você realmente precisar que seja realmente global em todos os lugares, como um integrado, adicione-o ao módulo integrado. Os detalhes exatos diferem entre Python 2.xe 3.x. No 3.x, funciona assim:
fonte
Como solução alternativa, você pode considerar a configuração de variáveis de ambiente na camada externa, como esta.
main.py:
mymodule.py:
Como precaução extra, trate do caso quando MYVAL não estiver definido dentro do módulo.
fonte
Uma função usa os globais do módulo em que está definida . Em vez de definir
a = 3
, por exemplo, você deve definirmodule1.a = 3
. Portanto, se você desejacur
disponibilizar como um em globalutilities_module
, definautilities_module.cur
.Uma solução melhor: não use globais. Passe as variáveis de que você precisa para as funções que precisam delas ou crie uma classe para agrupar todos os dados e passe-as ao inicializar a instância.
fonte
Este post é apenas uma observação sobre o comportamento do Python que encontrei. Talvez os conselhos que você leu acima não funcionem para você se você fez a mesma coisa que fiz abaixo.
Ou seja, tenho um módulo que contém variáveis globais / compartilhadas (conforme sugerido acima):
Então eu tive o módulo principal que importa o material compartilhado com:
e alguns outros módulos que realmente preencheram esses arrays. Eles são chamados pelo módulo principal. Ao sair desses outros módulos, posso ver claramente que os arrays estão preenchidos. Mas ao lê-los no módulo principal, eles estavam vazios. Isso foi muito estranho para mim (bem, eu sou novo em Python). No entanto, quando eu mudo a forma como eu importo o sharedstuff.py no módulo principal para:
funcionou (os arrays foram preenchidos).
Apenas dizendo'
fonte
A solução mais fácil para este problema específico teria sido adicionar outra função dentro do módulo que teria armazenado o cursor em uma variável global para o módulo. Então, todas as outras funções também poderiam usá-lo.
Módulo 1:
programa principal:
fonte
Como os globais são específicos do módulo, você pode adicionar a seguinte função a todos os módulos importados e usá-la para:
Então, tudo que você precisa para passar os globais atuais é:
fonte
Como não o vi nas respostas acima, pensei em adicionar minha solução alternativa simples, que é apenas adicionar um
global_dict
argumento à função que requer os globais do módulo de chamada e, em seguida, passar o dict para a função ao chamar; por exemplo:fonte
A maneira OOP de fazer isso seria tornar seu módulo uma classe em vez de um conjunto de métodos não acoplados. Em seguida, você pode usar
__init__
ou um método setter para definir as variáveis do chamador para uso nos métodos do módulo.fonte