Могу ли я использовать __init__.py для определения глобальных переменных?

130

Я хочу определить константу, которая должна быть доступна во всех подмодулях пакета. Я думал, что лучше всего будет в __init__.pyфайле корневого пакета. Но я не знаю, как это сделать. Предположим, у меня есть несколько подпакетов, каждый с несколькими модулями. Как я могу получить доступ к этой переменной из этих модулей?

Конечно, если это совершенно неправильно, и есть альтернатива лучше, я бы хотел знать об этом.

Андрей Вайна II
источник

Ответы:

196

Вы должны уметь их вставить __init__.py. Это происходит постоянно.

mypackage/__init__.py:

MY_CONSTANT = 42

mypackage/mymodule.py:

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

Затем импортируйте mymodule:

>>> from mypackage import mymodule
my constant is 42

Тем не менее, если у вас есть константы, было бы разумно (возможно, лучше всего) поместить их в отдельный модуль (constants.py, config.py, ...), а затем, если вы хотите, чтобы они были в пространстве имен пакета, импортируйте их.

mypackage/__init__.py:

from mypackage.constants import *

Тем не менее, это не включает автоматически константы в пространствах имен модулей пакета. Каждый из модулей в пакете по-прежнему должен будет явно импортировать константы либо из, mypackageлибо из mypackage.constants.

Джейсон Р. Кумбс
источник
19
Это должен был быть принятый ответ. Если вы работаете с Python 2.5 или выше, вы также можете использовать явный относительный импорт, как описано здесь : from . import MY_CONSTANT
ThatAintWorking
не работает ли второй способ только для констант? from mypackage.constants import *будет размещать копии MY_CONSTANTв каждом подмодуле, а не ссылку на одну и ту же переменную
hardmooth
@hardmooth: Не совсем так. Значения копируются по ссылке, поэтому, если вы измените MY_CONSTANTкакой-либо из модулей, он изменится везде. Если вы переназначаете MY_CONSTANTкакой-либо из модулей, это повлияет только на этот модуль. Если это ваше намерение, вы должны ссылаться на атрибут, то есть mypackage.constants.MY_CONSTANT.
Джейсон Р. Кумбс,
7
Один поймать на примере, если вы импортируете mymodule.pyв __init__.pyдо того, MY_CONSTANT = 42что не получится, потому что , когда импорт mymodule.py MY_CONSTANTне был определен. Так что нужно двигаться MY_CONSTANT = 42вышеimport mymodule
markmnl
как насчет переменной? Он спрашивает о переменных, а не о константах. Как Python обрабатывает переменную внутри пакета? Что делать, если переменная внутри пакета была изменена?
TomSawyer
31

Вы не можете сделать это. Вам нужно будет явно импортировать свои константы в пространство имен каждого отдельного модуля. Лучший способ добиться этого - определить ваши константы в модуле "config" и импортировать их везде, где вам это нужно:

# mypackage/config.py
MY_CONST = 17

# mypackage/main.py
from mypackage.config import *
Фердинанд Бейер
источник
Ага, мне нужен файл конфигурации. Я просто подумал, что init .py будет хорошим местом. Ваше решение звучит как стандартная практика. Это?
Андрей Вайна II
1
Хорошая точка зрения. Я не понимал, что вопрос заключается в том, чтобы константы автоматически помещались в пространство имен всех модулей пакета.
Джейсон Р. Кумбс,
Но каждый раз, когда скрипт импортирует config.py, код внутри выполняется. Что вы посоветуете, если код внутри config.py нужно запускать только один раз? Скажем, я читаю файл settings.json внутри config.py и не хочу открывать его каждый раз, когда импортирую config.py.
Augiwan
@UGS Python работает не так. Каждый модуль выполняется только один раз. Когда он импортируется во второй раз, модуль уже кэшируется sys.modules.
Фердинанд Бейер
@FerdinandBeyer Упс! Я забыл упомянуть, что импортирую config.py из нескольких скриптов, а не из одного и того же. Скажем, a.py импортирует config.py и b.py, а b.py импортирует config.py. Мне было интересно, можно ли убедиться, что код внутри config.py выполняется только один раз.
Augiwan
2

Вы можете определять глобальные переменные откуда угодно, но это действительно плохая идея. импортируйте __builtin__модуль и измените или добавьте атрибуты к этим модулям, и вдруг у вас появятся новые встроенные константы или функции. Фактически, когда мое приложение устанавливает gettext, я получаю функцию _ () во всех своих модулях, ничего не импортируя. Так что это возможно, но, конечно, только для проектов типа приложения, а не для повторно используемых пакетов или модулей.

И я думаю, никто бы все равно не рекомендовал эту практику. Что не так с пространством имен? В указанном приложении есть модуль версии, поэтому у меня есть «глобальные» переменные, например version.VERSION, version.PACKAGE_NAMEи т. Д.

u0b34a0f6ae
источник
0

Просто хотел добавить, что константы можно использовать с помощью файла config.ini и анализировать в скрипте с помощью библиотеки configparser. Таким образом, у вас могут быть константы для нескольких обстоятельств. Например, если у вас были константы параметров для двух отдельных запросов URL, просто пометьте их так:

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

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

Я нашел документацию на веб-сайте Python очень полезной. Я не уверен, есть ли какие-либо различия между Python 2 и 3, поэтому вот ссылки на оба:

Для Python 3: https://docs.python.org/3/library/configparser.html#module-configparser

Для Python 2: https://docs.python.org/2/library/configparser.html#module-configparser

Дэн Темкин
источник