Немного об импортах в питоне | Блог python программиста
Изображение гика

Блог питониста

Немного об импортах в питоне

12 ноября 2017 г.

Хотелось бы рассказать об одном моменте, связанном с системой импортов в питоне. Неподготовленному человеку может иногда показаться, что происходят нелогичные вещи, несоответствующие его ожиданиям. Так было со мной, когда я впервые столкнулся с данной проблемой.

Допустим есть такой проект:

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.

Метки

python
Если вам понравился пост, можете поделиться им в соцсетях: