Mam trzy moduły:
constants
, który zawiera załadowaną konfigurację i inne rzeczy w klasiemain
, który inicjujeconstants
kiedy jest uruchamianyuser
, który importujeconstants
i uzyskuje dostęp do jego konfiguracji.
constants
moduł (uproszczony) wygląda tak:
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)
Prosty obiekt, który powinien utrzymać konfigurację, nic przełomowego.
Funkcja populate_constants()
jest wywoływana z main
przy uruchomieniu programu.
Teraz dzieje się dziwność - kiedy importuję constants
moduł od user
w ten sposób constants
jest None
:
from toplevelpkg.constants import constants
print(constants)
None
Jeśli jednak zaimportuję to w ten sposób, constants
jest inicjowany tak, jak można by oczekiwać:
from toplevelpkg import constants
print(constants.constants)
<trumpet.constants.Constants object at 0x035AA130>
Dlaczego?
EDYTUJ: w moim kodzie funkcja próbująca odczytać constants
jest uruchamiany asynchronicznie przez await loop.run_in_executor(None, method_needing_import)
. Nie jesteś pewien, czy może to powodować problemy?
(i jako pytanie poboczne, czy dobrą praktyką jest posiadanie obiektu przechowującego konfigurację, który analizuje plik konfiguracyjny i podaje go jako zmienne członkowskie?)
Odpowiedzi:
2 dla odpowiedzi № 1Jest rzeczywiście różnica między
from mymodule import obj
(...)
do_something_with(obj)
i
import mymodule
(...)
do_something_with(mymodule.obj)
W pierwszym przypadku działa jako:
import mymodule
obj = mymodule.obj
del mymodule
co oznacza, że w tym momencie w bieżącym module, obj
jest „globalną” (co w Pythonie oznacza w rzeczywistości „modułowy”, a nie „obejmujący całą aplikację”) nazwę powiązaną z czymkolwiek mymodule.obj
był kiedy został zaimportowany (w Twoim przypadku : None
). Odtąd, mymodule.obj
i moduł-lokalny obj
imiona mieszkają w różnych przestrzeniach nazw (pierwsza w mymodule
przestrzeń nazw, druga w bieżącej przestrzeni nazw modułów) i ponowne wiązanie mymodule.obj
z dowolnego miejsca nic nie zmieni na to, co jest obecny moduł obj
jest zobowiązany. Właściwie to tak, jakbyś to robił:
a = 2
b = a
a = 4
Po trzecim oświadczeniu b
jest oczywiście nadal związany 2
- ponowne wiązanie a
do 4
nie wpływa b
.
W drugim przypadku (import mymodule
) to, co jest powiązane w przestrzeni nazw modułu importującego to całość mymodule
obiekt, więc jeśli mymodule.obj
odbiera (od wewnątrz mymodule
lub gdziekolwiek indziej) zmiana będzie widoczna w module importu. W tym przypadku jest to odpowiednik
a = {"x": 2}
b = a
a["x"] = 4
W takim przypadku zmiana będzie widoczna z b["x"]
również od tego czasu a
i b
są nadal związane z tym samym obiektem.
wrt / twoje pytanie poboczne: tak, posiadanie jakiegoś obiektu „config” jest dość powszechnym wzorcem. Możesz po prostu upewnić się, że możesz również zbudować go „od zera” (to znaczy, niekoniecznie z pliku konfiguracyjnego), aby ułatwić testowanie.