Почему для импорта Python требуется fromlist?



в Python, если вы хотите программно импортировать модуль, вы можете сделать:



module = __import__('module_name')


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



module = __import__('module_name.submodule')


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



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


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



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

376   3  

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.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. Предположим, у нас есть модуль, называемый С. ру и код:

  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

    Ничего не найдено.