/ / Importowanie zmiennej bezpośrednio daje inną wartość niż importowanie jej modułu w Pythonie - python, import python

Importowanie zmiennej bezpośrednio daje inną wartość niż importowanie jej modułu w Pythonie - python, python-import

Mam trzy moduły:

  • constants, który zawiera załadowaną konfigurację i inne rzeczy w klasie
  • main, który inicjuje constants kiedy jest uruchamiany
  • user, który importuje constants 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 № 1

Jest 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.