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

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.

Метки

Оставить комментарий

Нужен для связи
captcha

Комментарий отправлен

Спасибо! Он появится на странице после проверки.