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