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


130

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

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

Ответы:


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и т. Д.


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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.