Немного об импортах в питоне
Хотелось бы рассказать об одном моменте, связанном с системой импортов в питоне. Неподготовленному человеку может иногда показаться, что происходят нелогичные вещи, несоответствующие его ожиданиям. Так было со мной, когда я впервые столкнулся с данной проблемой.
Допустим есть такой проект:
project | main.py | test1.py | test2.py | config.py
main.py:
1 import config as conf 2 import test1 3 import test2 4 5 print(' in main') 6 print(conf.test_var) 7 test1.test1() 8 print(' again in main') 9 print(conf.test_var) 10 test2.test2()
test1.py:
1 import config as conf 2 3 4 def test1(): 5 print(' in test1, executing test1()') 6 conf.test_var = 'test1'
test2.py:
1 import config as conf 2 3 4 def test2(): 5 print(' in test2, executing test2()') 6 print(conf.test_var)
config.py:
1 test_var = 'initial_value'
Что будет если выполнить main.py? Сначала будет выведено начальное значение переменной. Затем будет вызвана функция test1, которая поменяет ее значение, будет выведено новое значение, но что будет потом в функции test2? Будет ли загружена заново переменная test_var? python main.py выведет следующее:
in main initial_value in test1, executing test1() again in main test1 in test2, executing test2() test1
Можно было подумать (так было со мной), что последняя строчка будет другой - что там тоже должна быть выведена строка "initial_value", поскольку в модуле test2 config вроде бы заново импортируется, но python кэширует импорты, поэтому значение переменной не обновляется, а остается такой же как и в функции test1.
test1.py:
1 import config as conf 2 3 4 def test1(): 5 print(' in test1, executing test1()') 6 print(id(conf.test_var)) 7 conf.test_var = 'test1' 8 print(id(conf.test_var))
test2.py:
1 import config as conf 2 3 4 def test2(): 5 print(' in test2, executing test2()') 6 print(id(conf.test_var)) 7 print(conf.test_var)
python main.py:
in main initial_value in test1, executing test1() 140355198581312 140355198588464 again in main test1 in test2, executing test2() 140355198588464 test1
Во-первых, при присваивании нового значения переменной test_var в функции test1 создается новая переменная, во-вторых, после изменения в функции test1 та же самая переменная test_var задействована в функции test2. Впрочем, такое поведение можно изменить, если принудительно перезагрузить config, test2.py:
1 # python2 2 import config as conf 3 4 5 def test2(): 6 print(' in test2, executing test2()') 7 print(id(conf.test_var)) 8 reload(conf) 9 print(id(conf.test_var)) 10 print(conf.test_var)
Если вы используете python3, то используйте следующий код для импорта reload, потому что она была перемещена:
1 import importlib 2 importlib.reload(module) 3 ...
python main.py:
in main initial_value in test1, executing test1() 140009528056384 140009528063536 again in main test1 in test2, executing test2() 140009528063536 140009528056384 initial_value
Теперь видно, что config был перезагружен в функции test2.py, и теперь в ней после перезагрузки config'a используется изначальное значение переменной test_var.
Вывод
Для опытных разработчиков этот пост не представляет какой-либо ценности, но если вы новичок в питоне, то возможно вам было полезно узнать, что питон кэширует импорты, но это можно обойти, используя функцию reload.