/ / Импортиране на променлива директно дава различна стойност от внасянето на неговия модул в Python - python, python-import

Промяната на импортирането директно дава различна стойност, отколкото импортирането на модула в Python - python, python-import

Имам три модула:

  • constants, която съдържа заредена конфигурация и други неща в клас
  • main, която се инициализира constants когато тече
  • user, които внасят constants и осъществява достъп до неговата конфигурация.

constants модул (опростен) изглежда така:

class Constants:
def __init__(self, filename):
# Read values from INI file
config = self.read_inifile(filename)
self.somevalue = config["ex"]["ex"]

def read_inifile(self, filename):
# reads inifile

constants: Constants = None

def populate_constants(filename):
global constants
constants = Constants(filename)

Един прост обект, който трябва да държи конфигурацията, нищо новаторско.

Функцията populate_constants() се нарича от main при стартиране на програмата.

Сега се случва странността - когато импортирам constants модул от user като този, constants е None:

from toplevelpkg.constants import constants
print(constants)

None

Ако я импортирам по този начин, constants се инициализира, както бихте очаквали:

from toplevelpkg import constants
print(constants.constants)

<trumpet.constants.Constants object at 0x035AA130>

Защо така?

EDIT: в моя код, функцията, която се опитва да прочете constants се изпълнява асинхронно чрез await loop.run_in_executor(None, method_needing_import), Не сте сигурни дали това може да доведе до проблеми?

(и като страничен въпрос, дали е добра практика да имате обект за задържане на конфигурация, който анализира конфигурационния файл и го предоставя като неговите променливи на член?)

Отговори:

2 за отговор № 1

Наистина има разлика между

from mymodule import obj
(...)
do_something_with(obj)

и

import mymodule
(...)
do_something_with(mymodule.obj)

В първия случай той действа като:

 import mymodule
obj = mymodule.obj
del mymodule

което означава, че в този момент в настоящия модул, obj е "глобално" (което в Python всъщност означава "модулно ниво", а не "име-на-приложение"), свързано с каквото и да е mymodule.obj беше когато е внесен (в твоя случай: None). От този момент нататък, mymodule.obj и модул-локален obj имена живеят в различни пространства за имена (първата в mymodule пространството от имена, второто в текущото пространство от имена на модула) и повторно свързване mymodule.obj отвсякъде няма да промени нищо до това, което настоящият модул obj е задължен. Всъщност точно така е, ако правите това:

a = 2
b = a
a = 4

След третото изявление, b очевидно все още е обвързан 2 - повторно подвързване a да се 4 няма въздействие b.

Във втория случай (import mymodule) какво е свързано в пространството от имена на модула за импортиране е цялото mymodule обект, така че ако mymodule.obj получава отскачане (отвътре mymodule или някъде другаде) промяната ще бъде видима в модула за импортиране. В този случай това е еквивалентно на

a = {"x": 2}
b = a
a["x"] = 4

В такъв случай промяната ще бъде видима от b["x"] оттогава a и b все още са обвързани със същия обект.

wrt / вашия страничен въпрос: да, като някои "config" обект е доста общ модел. Просто може да искате да се уверите, че можете да го изградите "от нулата" (също, не е задължително от конфигурационен файл), за да направите unittesting по-лесно.