Почему для импорта Python требуется fromlist?
в Python, если вы хотите программно импортировать модуль, вы можете сделать:
module = __import__('module_name')
если вы хотите импортировать подмодуль, вы могли бы подумать, что это будет простой вопрос:
module = __import__('module_name.submodule')
конечно, это не работает; вы просто получите module_name еще раз. Вы должны сделать:
module = __import__('module_name.submodule', fromlist=['blah'])
почему? фактическое значение fromlist кажется, это не имеет значения, пока он не пуст. Какой смысл требовать аргумента, а затем игнорировать его ценности?
большинство вещей в Python, похоже, делается по уважительной причине, но для жизни меня я не могу придумать никакого разумного объяснения этому поведению.
3 ответов:
на самом деле, поведение
__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, который является объектом модуля, который имеет . Итак,__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атрибут from. Реализация могла бы решить сделать это такimportзаявление делает дополнительную работу, разделяя имя пакета на.как
Я все еще чувствую себя странно, когда я читаю ответ, поэтому я попробовал ниже примеры кода.
во-первых, попробуйте построить ниже структуру файла:
этоtmpdir |A |__init__.py | B.py | C.pypackageиBилиCэтоmodule. Поэтому, когда мы пробуем такой код в ipython:во-вторых, запустите пример кода в ipython:
In [2]: kk = __import__('A',fromlist=['B']) In [3]: dir(kk) Out[3]: ['B', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']похоже, что fromlist работает так, как мы ожидали. Но вещи становятся проводными, когда мы пытаемся сделать то же самое на
module. Предположим, у нас есть модуль, называемый С. ру и код:handlers = {} def hello(): print "hello" test_list = []Итак, теперь мы пытаемся сделать то же самое на нем.
In [1]: ls C.py In [2]: kk = __import__('C') In [3]: dir(kk) Out[3]: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'handlers', 'hello', 'test_list']Итак, когда мы просто хотим импортировать test_list, это работает?
In [1]: kk = __import__('C',fromlist=['test_list']) In [2]: dir(kk) Out[2]: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'handlers', 'hello', 'test_list']как показывает результат, когда мы пытаемся использовать fromlist на
module, а неpackage, fromlist param не помогает вообще, потому чтоmoduleбыл составлен. После того, как он импортирован, нет никакого способа игнорировать другие.
ответ можно найти в документации для
__import__:fromlist должен быть списком имен для эмуляции
from name import ..., или пустой список для эмуляцииimport name.при импорте модуля из пакета, обратите внимание, что
__import__('A.B', ...)возвращает пакет A, когда fromlist пуст, но его подмодуль B, когда fromlist не пуст.так что в основном, это просто, как реализация
__import__работает: если вы хотите подмодуль, вы проходитеfromlistсодержащий то, что вы хотите импортировать из подмодуля, и реализацию if__import__таков, что подмодуль возвращается.дальнейших объяснений
я думаю, что семантика существует так, что возвращается наиболее релевантный модуль. Другими словами, скажем, у меня есть пакет
fooсодержащих модульbarС функциейbaz. Если Я:import foo.barтогда я имею в виду
bazкакfoo.bar.baz()это как
__import__("foo.bar", fromlist=[]).если вместо этого я импортирую с:
from foo import barтогда я имею в виду
bazкак бар.баз()который был бы похож на
__imoort__("foo.bar", fromlist=["something"]).если я это сделаю:
from foo.bar import bazтогда я имею в виду
bazкакbaz()это как
__import__("foo.bar", fromlist=["baz"]).поэтому в первом случае мне пришлось бы использовать полное имя, следовательно
__import__возвращает имя модуля вы бы использовали для ссылки на импортированные элементы, которые являютсяfoo. В последнем случае,barявляется наиболее конкретным модулем, содержащим импортированные элементы, поэтому имеет смысл, что__import__вернетfoo.barмодуль.второй случай немного странный, но я предполагаю, что он был написан таким образом, чтобы поддерживать импорт модуля с помощью
from <package> import <module>синтаксис, и в этом случаеbarпо-прежнему является наиболее конкретным модулем для возврата.
Comments