Подтвердить что ты не робот

Почему "импорт" реализован таким образом?

>>> import math
>>> math.pi
3.141592653589793
>>> math.pi = 3
>>> math.pi
3
>>> import math
>>> math.pi
3

Начальный вопрос: почему я не могу получить math.pi назад?

Я думал, что import будет импортировать все определенные переменные и функции в текущую область. И если имя переменной уже существует в текущей области, то оно заменит его.

Да, он его заменяет:

>>> pi = 3
>>> from math import *
>>> pi
3.141592653589793

Тогда я подумал, что, возможно, назначение math.pi = 3 действительно изменило свойство в math class (или оно math module?), которое импортировало import math.

Я был прав:

>>> import math
>>> math.pi
3.141592653589793
>>> math.pi = 3
>>> from math import *
>>> pi
3

Итак, кажется, что:
Если вы выполняете import x, тогда он импортирует x как класс. И если вы внесете изменения в x.property, изменение будет сохраняться в модуле, чтобы каждый раз, когда вы импортируете его снова, это модифицированная версия.

Реальный вопрос:

  • Почему import реализован таким образом? Почему бы не позволить каждой import math импортировать новую, немодифицированную копию math? Почему оставить импортированный math открытым для изменения?
  • Есть ли способ обхода, чтобы получить math.pi назад после выполнения math.pi = 3 (кроме math.pi = 3.141592653589793, конечно)?
  • Первоначально я думал, что import math предпочтительнее from math import *. Но это поведение меня беспокоит, что кто-то другой может изменить мой импортированный модуль, если я сделаю это таким образом... Как мне сделать import?
4b9b3361

Ответ 1

Модуль может быть импортирован много раз. Оператор import просто загружает ссылку из sys.modules. Если оператор import также перезагрузил модуль с диска, он будет довольно медленным. Изменение такого модуля очень необычно и выполняется только в редких, задокументированных обстоятельствах, поэтому вам не нужно беспокоиться.

Как reload модуль:

>>> import imp
>>> imp.reload(math)
<module 'math' (built-in)>
>>> math.pi
3.141592653589793

Ответ 2

Python создает только одну копию любого данного модуля. Импорт модуля неоднократно повторяет оригинал. Это связано с тем, что если модули A и B импортировали C и D, которые импортировали E и F и т.д., C и D будут загружаться дважды, а E и F будут загружаться 4 раза и т.д. При любых, но самых тривиальных зависимостях графиков, вы потратили бы несколько минут на загрузку избыточных модулей до исчерпания памяти. Кроме того, если A импортированный B и B импортировал A, вы бы застряли в рекурсивном цикле и, опять же, исчерпали память, не делая ничего полезного.

Решение: Не вкручивайте содержимое других модулей.. Если вы это сделаете, это изменение в интерпретаторе. Бывают ситуации, когда вы захотите это сделать, поэтому Python позволяет вам, но обычно это плохая идея.

Ответ 3

Поведение импорта предназначено для обеспечения состояния модулей. Например, модуль, который запускает код инициализации, может иметь разные виды поведения, основанные на том, что происходит во время init (хорошим примером является модуль os, который прозрачно загружает разные версии подмодуля пути в зависимости от того, на какой ОС вы находитесь), Обычное поведение существует, чтобы позволить большому количеству разных кодов обращаться к модулю без повторного запуска инициализации снова и снова. Кроме того, модули функционируют как статические классы на других языках - они могут поддерживать состояние и часто используются в качестве альтернативы глобальным переменным: например, вы можете использовать локальный модуль для установки локальных переменных культуры (формат валюты и т.д.) - вызов locale.setlocale в одной части вашего кода и local.getlocale в другой - хорошая альтернатива созданию глобальной переменной.

Ваш пример, конечно, указывает на слабость. Один из классических принципов python -

Мы все взрослые здесь

Язык не обеспечивает большую часть функций управления конфиденциальностью, которые вы найдете, например, в Java или С#, которые позволяют автору блокировать содержимое модуля или класса. Вы можете, если вы чувствуете себя злонамеренным (или просто самоубийством), выполняете именно то, что сделано в вашем примере: измените pi на равный 3 или превратите функцию в переменную или всевозможные другие неприятные вещи. Язык не предназначен для того, чтобы сделать это сложным - это зависит от того, отвечают ли разработчики.

@Josh Ли ответ показывает, как использовать перезагрузку, что является правильным способом обновления модуля к нему на основе диска. Мудрость использования перезагрузки зависит в основном от того, сколько кода инициализации находится в модуле, а также в Интернете других модулей, которые импортируют или импортируются данным модулем.