2010-04-27 6 views
67

В Python, если вы хотите программно импортировать модуль, вы можете сделать:Почему Python __import__ требует fromlist?

module = __import__('module_name') 

Если вы хотите импортировать подмодуль, вы думаете, что это было бы простой вопрос:

module = __import__('module_name.submodule') 

Конечно, это не работает; вы снова получите module_name. Вы должны:

module = __import__('module_name.submodule', fromlist=['blah']) 

Почему? Фактическое значение fromlist, похоже, не имеет значения, если оно не пустое. Какой смысл требовать аргумент, а затем игнорировать его значения?

Большинство вещей в Python, кажется, сделано по уважительной причине, но для моей жизни я не могу придумать разумного объяснения этого поведения.

ответ

116

Фактически поведение __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 заявления.)

2

Ответ можно найдено найти в документации для __import__:

fromlist должен быть список имен для эмуляции from name import ..., или пустой список, чтобы подражать import name.

При импорте модуля из пакета обратите внимание, что __import__('A.B', ...) возвращает пакет A, когда fromlist пуст, но его подмодуль B, когда fromlist не пуст.

Так в основном, это просто, как реализация __import__ работ: если вы хотите подмодуль, вы передаете fromlist содержащего то, что вы хотите импортировать из субмодуля, и реализация, если __import__ такова, что подмодуль возвращается ,

Дальнейшее объяснение

Я думаю, что существует семантика так, что самый соответствующий модуль возвращается. Другими словами, скажем, у меня есть пакет foo, содержащий модуль bar с функцией baz. Если я:

import foo.bar 

Тогда я имею в виду, как baz

foo.bar.baz() 

Это как __import__("foo.bar", fromlist=[]).

Если вместо того, чтобы импортировать с:

from foo import bar 

Тогда я обращаюсь к baz, как 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 по-прежнему является наиболее конкретным модулем для возврата.

+0

Говоря «вот как работает реализация», не отвечает на мой вопрос. Почему это работает? Высказывание формы «для эмуляции имени импорта ...» ближе, но при каких обстоятельствах вам это нужно? Исход из списка не имеет отличия от того, как работает __import__, поэтому я не вижу, где есть случай, когда вам нужно передать его, чтобы подражать чему-либо, кроме того, что должно быть очевидным поведением функции. – ieure

+1

Вы правы, это попрошайничает вопрос. Я обновил свой ответ, чтобы дать более релевантный ответ. – mipadi

4

Я все еще чувствую себя странно, когда читаю ответ, поэтому попробовал приведенные ниже примеры кода.

Во-первых, попытаться построить ниже структуры файла:

tmpdir 
    |A 
    |__init__.py 
    | B.py 
    | C.py 

Теперь А является package и 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. Предположим, что в нем есть модуль C.py и код:

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 пары не помогают вообще, потому что module был составлен. После его импорта невозможно игнорировать другие.

Смежные вопросы