Немного об импортах в питоне
Хотелось бы рассказать об одном моменте, связанном с системой импортов в питоне. Неподготовленному человеку может иногда показаться, что происходят нелогичные вещи, несоответствующие его ожиданиям. Так было со мной, когда я впервые столкнулся с данной проблемой.
Допустим есть такой проект:
project
| main.py
| test1.py
| test2.py
| config.py
main.py:
1import config as conf 2import test1 3import test2 4 5print(' in main') 6print(conf.test_var) 7test1.test1() 8print(' again in main') 9print(conf.test_var) 10test2.test2()
test1.py:
1import config as conf 2 3 4def test1(): 5 print(' in test1, executing test1()') 6 conf.test_var = 'test1'
test2.py:
1import config as conf 2 3 4def test2(): 5 print(' in test2, executing test2()') 6 print(conf.test_var)
config.py:
1test_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:
1import config as conf 2 3 4def 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:
1import config as conf 2 3 4def 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 2import config as conf 3 4 5def 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, потому что она была перемещена:
1import importlib 2importlib.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.