На самом деле, поведение __import__()
полностью связано с реализацией оператора import
, который вызывает __import__()
. Есть в основном пять немного разных способов __import__()
, которые можно назвать import
(с двумя основными категориями):
import pkg
import pkg.mod
from pkg import mod, mod2
from pkg.mod import func, func2
from pkg.mod import submod
В первом и во втором случае оператор import
должен присвоить «крайнему левому» объекту модуля «самое левое» имя: pkg
. После import pkg.mod
вы можете сделать pkg.mod.func()
, потому что оператор import
ввел локальное имя pkg
, которое является модульным объектом с атрибутом mod
. Таким образом, функция __import__()
должна возвращать «самый левый» объект модуля, чтобы его можно было присвоить pkg
. Эти два оператора импорта, таким образом, переводятся в:
pkg = __import__('pkg')
pkg = __import__('pkg.mod')
В третьем, четвертом и пятом случаях оператор import
должен выполнять больше работы: он должен присваивать (потенциально) несколько имен, которые он должен получить из объекта модуля. Функция __import__()
может возвращать только один объект, и нет никакой реальной причины заставлять ее извлекать каждое из этих имен из объекта модуля (и это сделало бы реализацию намного более сложной.) Таким образом, простой подход будет выглядеть примерно так ( для третьего случая):
tmp = __import__('pkg')
mod = tmp.mod
mod2 = tmp.mod2
Однако это не будет работать, если pkg
- это пакет, а mod
или mod2
- это модули в этом пакете , которые еще не импортированы , как в третьем и пятом дело. Функция __import__()
должна знать, что mod
и mod2
- это имена, которые оператор import
хочет иметь доступными, чтобы она могла видеть, являются ли они модулями, и пытается импортировать их тоже. Таким образом, вызов ближе к:
tmp = __import__('pkg', fromlist=['mod', 'mod2'])
mod = tmp.mod
mod2 = tmp.mod2
, что заставляет __import__()
попытаться загрузить pkg.mod
и pkg.mod2
, а также pkg
(но если mod
или mod2
не существует, это не ошибка в вызове __import__()
; создание ошибки оставлено для оператора import
.) Но это все еще не то, что нужно для четвертого и пятого примера, потому что если бы вызов был таким:
tmp = __import__('pkg.mod', fromlist=['submod'])
submod = tmp.submod
затем tmp
в конечном итоге будет pkg
, как и раньше, а не модулем pkg.mod
, от которого вы хотите получить атрибут submod
. Реализация могла бы сделать это так, чтобы оператор import
выполнял дополнительную работу, разбивая имя пакета на .
, как уже делает функция __import__()
, и обходя имена, но это означало бы дублирование некоторых усилий. Таким образом, вместо этого реализация __import__()
возвращает самый правый модуль вместо самый левый один тогда и только тогда, когда из списка передан, а не пустой.
(Синтаксис import pkg as p
и from pkg import mod as m
ничего не меняет в этой истории, кроме того, какие локальные имена назначены - функция __import__()
не видит ничего другого при использовании as
, все остается в import
реализация оператора.)