Имам три модула:
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 по-лесно.