Чи можу я використовувати __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

Потім імпортуйте мій модуль:

>>> 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 буде гарним місцем. Ваше рішення звучить як стандартна практика. Є це?
Андрій Важна ІІ

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, я отримую функцію _ () у всіх своїх модулях, не імпортуючи нічого. Це можливо, але, звичайно, лише для проектів типу Application, а не для багаторазових пакетів або модулів.

І я думаю, ніхто не рекомендував би цю практику в будь-якому випадку. Що не так з простором імен? Згаданий додаток має модуль версії, так що у мене є "глобальні" змінні, наприклад 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.