Posso usar __init__.py para definir variáveis ​​globais?

130

Eu quero definir uma constante que deve estar disponível em todos os submódulos de um pacote. Eu pensei que o melhor lugar seria no __init__.pyarquivo do pacote raiz. Mas eu não sei como fazer isso. Suponha que eu tenha alguns subpacotes e cada um com vários módulos. Como posso acessar essa variável desses módulos?

Claro, se isso estiver totalmente errado e houver uma alternativa melhor, eu gostaria de saber.

Andrei Vajna II
fonte

Respostas:

196

Você deve poder colocá-los __init__.py. Isso é feito o tempo todo.

mypackage/__init__.py:

MY_CONSTANT = 42

mypackage/mymodule.py:

from mypackage import MY_CONSTANT
print "my constant is", MY_CONSTANT

Em seguida, importe mymodule:

>>> from mypackage import mymodule
my constant is 42

Ainda assim, se você possui constantes, seria razoável (provavelmente as melhores práticas) colocá-las em um módulo separado (constants.py, config.py, ...) e, em seguida, se você as quiser no espaço para nome do pacote, importe eles.

mypackage/__init__.py:

from mypackage.constants import *

Ainda assim, isso não inclui automaticamente as constantes nos espaços para nome dos módulos do pacote. Cada um dos módulos no pacote ainda precisará importar constantes explicitamente de mypackageou de mypackage.constants.

Jason R. Coombs
fonte
19
Essa deveria ter sido a resposta aceita. Se você estiver trabalhando com o Python 2.5 ou superior, também poderá usar uma importação relativa explícita, bem como descrito aqui : from . import MY_CONSTANT
ThatAintWorking
a segunda maneira não funciona apenas para constantes? from mypackage.constants import *vai colocar cópias MY_CONSTANTem cada sub-módulo, em vez de uma referência à mesma variável
hardmooth
@hardmooth: Não exatamente. Os valores são copiados por referência; portanto, se você fizer uma mutação MY_CONSTANTem qualquer um dos módulos, ele será alterado em todos os lugares. Se você fosse redesignar MY_CONSTANTem qualquer um dos módulos, isso afetaria apenas esse módulo. Se essa é a sua intenção, você deve fazer referência por atributo, ie mypackage.constants.MY_CONSTANT.
Jason R. Coombs
7
Um prendedor com o exemplo é se importar mymodule.pyem __init__.pyantes MY_CONSTANT = 42que falhará porque ao importar mymodule.py MY_CONSTANTainda não foi definido. Então, precisamos seguir MY_CONSTANT = 42acimaimport mymodule
markmnl 16/11
como é a variável? É perguntar sobre variáveis, não constantes. Como python trata variável dentro do pacote? E se a variável dentro do pacote foi alterada?
TomSawyer
31

Você não pode fazer isso. Você precisará importar explicitamente suas constantes para o espaço de nome de cada módulo individual. A melhor maneira de conseguir isso é definir suas constantes em um módulo "config" e importá-lo para qualquer lugar que você precisar:

# mypackage/config.py
MY_CONST = 17

# mypackage/main.py
from mypackage.config import *
Ferdinand Beyer
fonte
Sim, um arquivo de configuração é o que eu gostaria. Eu apenas pensei que init .py seria um bom lugar. Sua solução parece uma prática padrão. É isso?
Andrei Vajna II
1
Bom ponto. Não sabia que a pergunta era colocar as constantes automaticamente no espaço para nome de todos os módulos do pacote.
Jason R. Coombs
Mas toda vez que um script importa o config.py, o código interno é executado. O que você recomenda se o código dentro do config.py for executado apenas uma vez? Digamos que estou lendo um arquivo settings.json dentro do config.py e não quero abri-lo () toda vez que importo o config.py.
Augiwan 3/07/14
@UGS Não é assim que o Python funciona. Cada módulo é executado apenas uma vez. Quando é importado pela segunda vez, o módulo já está armazenado em cache sys.modules.
Ferdinand Beyer
@FerdinandBeyer Oops! Esqueci de mencionar que estou importando o config.py de vários scripts e não o mesmo script. Digamos que a.py esteja importando config.py & b.py e b.py esteja importando config.py. Eu queria saber se é possível garantir que o código dentro do config.py seja executado apenas uma vez.
Augiwan 3/07/14
2

Você pode definir variáveis ​​globais de qualquer lugar, mas é uma péssima idéia. importe o __builtin__módulo e modifique ou adicione atributos a esses módulos e, de repente, você terá novas constantes ou funções internas. De fato, quando meu aplicativo instala o gettext, recebo a função _ () em todos os meus módulos, sem importar nada. Portanto, isso é possível, mas é claro, apenas para projetos do tipo Aplicativo, não para pacotes ou módulos reutilizáveis.

E acho que ninguém recomendaria essa prática de qualquer maneira. O que há de errado com um espaço para nome? O aplicativo possui o módulo version, para que eu tenha variáveis ​​"globais" disponíveis version.VERSION, como version.PACKAGE_NAMEetc.

u0b34a0f6ae
fonte
0

Só queria adicionar que as constantes podem ser empregadas usando um arquivo config.ini e analisadas no script usando a biblioteca configparser. Dessa forma, você pode ter constantes para várias circunstâncias. Por exemplo, se você tivesse constantes de parâmetro para duas solicitações de URL separadas, apenas as rotule da seguinte forma:

mymodule/config.ini
[request0]
conn = 'admin@localhost'
pass = 'admin'
...

[request1]
conn = 'barney@localhost'
pass = 'dinosaur'
...

Achei a documentação no site do Python muito útil. Não tenho certeza se existem diferenças entre Python 2 e 3, então aqui estão os links para ambos:

Para Python 3: https://docs.python.org/3/library/configparser.html#module-configparser

Para Python 2: https://docs.python.org/2/library/configparser.html#module-configparser

Dan Temkin
fonte