#python #import #module
Вопрос:
Допустим, у вас есть два модуля mod1.py
и mod2.py
.
В mod1.py
вы импортируете внешний (в пакет, который вы пишете) модуль, скажем numpy
, и в mod2.py
вы импортируете mod1
:
Внутри mod1.py
:
import numpy as np
Внутри mod2.py
:
import mod1
Теперь, если строка кода внутри mod2
вызывает np
это вызывает ошибку:
Ошибка имени: имя » np » не определено
Как я могу избежать импорта внешних модулей в каждый модуль (= файл) моего пакета?
Ответ №1:
import
может делать две вещи:
- Создайте модуль
- Определите новую переменную в текущей области видимости, привязанную к модулю
Модуль foo
будет создаваться только один раз для каждого процесса, независимо от того, сколько раз import foo
он выполняется. Однако import foo
всегда будет привязывать модуль к имени foo
, даже если foo
он уже привязан (к этому модулю или какому-либо другому значению) в текущей области.
import numpy as np
привязывает имя np
к numpy
модулю в глобальной области mod1
.
import mod1
связывает только имя mod1
; оно не переносит глобальные переменные mod1
в глобальную область действия mod2
. Для этого вам понадобится что-то вроде
from mod1 import np
или просто используйте mod1.np
внутри mod2
.
То, что вы, похоже, ищете,-это способ поместить np
в пространство имен для всего процесса, доступное из любого модуля. В Python есть только одно такое пространство имен, встроенное пространство имен, но вы не можете добавлять к нему имена. У вас есть только отдельные модули-глобальные пространства имен.
Выше я упоминал, что модуль создается только один раз. Это связано с тем, что import
сначала будет проверено, существует ли уже запрошенный модуль sys.modules
. Вы можете получить доступ np
из любого места после того, как он был импортирован один раз с помощью
sys.modules['numpy'] # The "real" name, not the import-defined alias
Однако нет никакой гарантии, что numpy
это еще не определено, и вам все равно придется импортировать sys
, чтобы получить доступ sys.modules
, так что это ничего не даст вам по сравнению с простым использованием
import numpy as np
куда захочешь np
.
Комментарии:
1. То, что вы, похоже, ищете,-это способ поместить np в пространство имен для всего процесса, доступное из любого модуля. Это именно то, что я искал. Спасибо вам за ваш ответ.
Ответ №2:
Здесь нужно подумать о двух вещах: об импорте модулей и об именовании этих импорта.
С вашей точки зрения, эти проблемы одинаковы: если вам нужно что-то в пространстве имен, вы импортируете это:
# mod1.py
import numpy as np
Другого способа получить что-либо в пространство имен вашего модуля нет. (Хорошо, нет другого способа, который не включал бы в себя возню с sys.modules
тем, чтобы делать то же самое).
Но что здесь сделал питон? Во-первых, он заглянул numpy
внутрь sys.modules
. Если его там нет, он загружает numpy и вставляет в него загруженный модуль sys.modules["numpy"]
. Затем он привязывает локальное имя np
, на которое указывает sys.modules["numpy"]
. Таким образом, если вы импортируете mod1
, вы можете получить доступ к его импорту:
#mod2.py
import mod1
mod1.np
(В стороне: это строгое соблюдение пространств имен является большим преимуществом и делает python гораздо менее восприимчивым к ошибкам случайного столкновения имен. Это упрощает вашу работу в качестве программиста, так как вам не нужно беспокоиться о том, что имена в импортированном модуле будут перезаписаны другими материалами, поэтому вам не нужно прибегать к таким вещам, как функции именования $get
или что-то еще, «очень маловероятное», которое будет использоваться).
Производительность
Означает ли это, что python загрузит один и тот же модуль несколько раз, если вы импортируете его несколько раз? Нет. Python импортирует модуль только один раз: после этого он просто привязывает локальное имя, указывающее на модуль sys.modules
. Таким образом, единственное наказание за выполнение:
#mod2
import numpy as np
import mod1
np
Это привязка имени, что тривиально (если вас это так волнует, вы не хотите использовать python). Для этого нет никаких причин:
# mod2.py
from mod1 import np
np
если только не проще не думать о том, откуда берутся ваши функции (вы часто будете видеть, что для удобства вы можете импортировать x
из библиотеки y
, например, импортировать компоненты Starlette
напрямую из FastApi
).
Будучи Декларативным
Управление пространствами имен подобным образом имеет одно огромное преимущество: когда я читаю ваш код, я точно знаю, откуда function_xyz()
он берется. Либо вы определили его в области, либо импортировали в эту область. Сравните это, например, с JS или R, когда я должен спросить—откуда именно берется xyz? а потом иди и посмотри его. По той же причине большинство линтеров рассердятся на вас, если вы напишете
from numpy import *
И настаивайте на том, чтобы вы явно импортировали то, что вам нужно.
Комментарии:
1. такое строгое соблюдение пространств имен является большим благом и делает python гораздо менее восприимчивым к ошибкам столкновения случайных имен. Это упрощает вашу работу в качестве программиста,[…] иначе «очень маловероятно» будет использоваться) Если я правильно понял: никто не использует этот синтаксис (практика noob), но вы, кажется, рекомендуете его ?
2. я имел в виду следующее: в отличие от других языков, где вы ожидаете , что ваши модули будут помещены в чужое пространство имен, или где существует только глобальное пространство имен , вам не нужно беспокоиться об этом, если люди этого не делают
from yourmodule import *
, что в любом случае является плохой практикой. В языках, где это неверное предположение, если вы ожидаете, что ваш код будет использоваться везде, вам придется очень серьезно подумать о том, как вы называете вещи. В python вы можете положиться на то, что люди делаютimport yourmodule; yourmodule.thing
, и не беспокоиться о том, есть ли у них athing
в их пространстве имен.3. Я открыт для предложений по более четкой формулировке ответа. Я начал этот ответ до того, как был опубликован другой ответ, но мы рассматриваем по существу одну и ту же тему. Я рассказал немного подробнее, чтобы оправдать сохранение этого.
4. Ваш ответ в порядке, спасибо :).