`del` на пакете имеет какую-то память
del
Кажется, у меня есть память, которая меня озадачивает. См. Следующее:
In [1]: import math
In [2]: math.cos(0)
Out[2]: 1.0
In [3]: del math.cos
In [4]: math.cos(0)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-4-9cdcc157d079> in <module>()
----> 1 math.cos(0)
AttributeError: module 'math' has no attribute 'cos'
Fine. Посмотрим, что произойдет, если мы удалим весь математический пакет:
In [5]: del math
In [6]: math.cos(0)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-6-9cdcc157d079> in <module>()
----> 1 math.cos(0)
NameError: name 'math' is not defined
Итак, теперь сама математика ушла, как и ожидалось.
Теперь снова импортируйте математику:
In [7]: import math
In [8]: math.cos(0)
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-8-9cdcc157d079> in <module>()
----> 1 math.cos(0)
AttributeError: module 'math' has no attribute 'cos'
Итак, как-то интерактивный python помнит, что math.cos был удален специально даже после того, как мы удалили весь математический пакет и снова импортировали его.
Где питон хранит эти знания? Можем ли мы получить к нему доступ? Можем ли мы изменить его?
Ответы
Ответ 1
Я бы сказал, что пакет по-прежнему считается импортированным. Поэтому выполнение import math
снова просто переопределяет имя, но со старым содержимым.
Вы можете использовать reload
, чтобы убедиться, что ваш модуль снова цел, за исключением того, что некоторым версиям python требуется также удалить запись в sys.modules
, что делает использование reload
избыточным:
import math
del math.cos
del math
sys.modules.pop("math") # remove from loaded modules
import math
print(math.cos(0)) # 1.0
(эта разница между различными версиями python, reload
и import
обсуждается в следующем вопросе: Должен importlib.reload восстановить удаленный атрибут в Python 3.6?)
Ответ 2
Пакет только считывается с диска один раз, а затем сохраняется в памяти как изменяемый singleton. Во второй раз, когда вы импортируете его, вы получаете тот же самый синглтон, который вы ранее импортировали, и он по-прежнему не имеет своего cos
. del math
просто удаляет локальное имя для него, он не "не импортирует" пакет из общего Python.
Ответ 3
del math
не удаляет пакет вообще, он просто удаляет локальное имя math
в текущем модуле.
Как и любой другой объект, если какие-либо другие ссылки на математический модуль существуют где угодно, он сохраняется в памяти.
И, в частности, sys.modules
всегда является словарем всех загруженных модулей, поэтому по крайней мере там всегда есть ссылка.
Изменить: Но есть способ действительно перезагрузить модуль, imp.reload
.
К сожалению, я не могу заставить его работать для этого случая, перезагрузка требует случайного модуля (возможно, для создания части компилируемого файла Python), для случайного модуля требуется math.cos
, и он исчез. Даже при импорте random
сначала нет ошибки, но math.cos
не появляется снова; Я не знаю, почему, может быть, потому, что это встроенный модуль.