Метка: importlib

Перезагрузка модулей Python

Пусть в файле my_module.py написано определение класса:

class A: ...

Пишем такой код в другом файле:

from my_module import A
a = A()
from my_module import A

print(isinstance(a, A))

Ответ – True. Система модулей Python только единожды будет запускать каждый импорируемый файл. Второй import не возымеет действия, и класс А будет тем же, что и был раньше.

Бонус: если вам нужно принудительно перезагрузить модуль – воспользуйтесь функцией reload из importlib. Попробуем. В файл mymodule.py напишем:

class A:
    # будем видеть, когда класс загружен
    print('loaded class A')

В другой файле:

from importlib import reload

import mymodule
a = my_module.A()
mymodule = reload(mymodule)

print(isinstance(a, mymodule.A))

Вывод программы:

loaded class A
loaded class A
False

Запустить ход.

Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈 

Узнать тип type() и проверить тип isinstance()

В Python у нас утиная динамическая типизация, поэтому бывает что нужно узнать тип переменной. Функция type() возвращает тип аргумента или, учитывая, что в Python – все класс, то класс аргумента. Результат можно сравнить с известным типом:

>>> i, s = 10, "hello"
>>> type(i)
<class 'int'>
>>> type(i) is int
True
>>> type(s) is str
True
>>> class A: pass
...
>>> a = A()
>>> type(a) is A
True

Можно создать экземпляр объекта того же класса, что и переменная:

>>> new_a = type(a)()
>>> type(new_a) == type(a)
True

⚠️ Нужно знать! type() не принимает во внимание наследование. Тип наследника отличается от типа родителя:

>>> class B(A): pass
...
>>> type(A()) is type(B())
False

Лучший способ проверить типы – функция isinstance(x, type) (instance англ. – экземпляр). Она возвращает True, если первый аргумент является экземпляром класса во втором аргументе:

>>> isinstance(i, int)
True
>>> isinstance(s, str)
True
>>> isinstance(a, A)
True

Функция поддерживает наследование:

class A: pass
class B(A): pass
b = B()
>>> isinstance(b, A)
True

И самое крутое: вторым аргументом допускается передать кортеж из типов, и isinstance вернет True, если хоть один из типов в кортеже подходит:

>>> isinstance(i, (int, float))
True
>>> isinstance(a, (A, B))
True

Загадка:

class A: ...
a = A()
class A: ...
print(isinstance(a, A))

Правильный ответ был False!

Объяснение. Динамическая натура Python позволяет переопределить класс во время интерпретации. Помните, как недавно я рассказывал про декораторы класса? Там мы подменяли один класс другим. Вот это из той же оперы. Тут мы подменили один класс, другим классом, отвязав имя А от старого класса и привязав его к новому. Старый класс А остался жив только как класс объекта в переменной a. Старого и нового классов разные адреса (id):

class A: ...
print(id(A))  # 140479777819720

a = A()

class A: ...
print(id(A))  # 140479777809672

isinstance(a, A)  # False

Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈