Проблема с python и __import__

Извините за общий заголовок, я изменю его, как только пойму источник своей проблемы. У меня следующая структура:

foo/
foo/__init__.py
foo/bar/
foo/bar/__init__.py
foo/bar/some_module.py

Когда я пытаюсь импортировать some_module следующим образом:

from foo.bar import some_module

Работает как часы. Но для меня это бесполезно, так как я знаю только имя модуля, который нужно импортировать во время выполнения. поэтому, если я попытаюсь:

from foo.bar import *
mod=__import__('some_module')

Я получаю сообщение об ошибке. Я делаю что-то неправильно? Есть лучший способ это сделать? и почему это происходит?

Это почему? Я не совсем уверен, что полностью понимаю концепцию пакетов Python. Я думал, что они эквивалентны пакетам Java и, следовательно,


person olamundo    schedule 27.08.2009    source источник
comment
Что говорится в сообщении об ошибке?   -  person ewall    schedule 27.08.2009
comment
ваш some_module уже импортирован!   -  person SilentGhost    schedule 27.08.2009


Ответы (3)


Я считаю, что правильный способ сделать это:

mod = __import__('foo.bar', fromlist = ['some_module'])

Таким образом, даже часть «foo.bar» может быть изменена во время выполнения. В результате some_moduleбудет доступен как mod.some_module; используйте getattr, если вы хотите использовать его в отдельной переменной:

the_module = getattr(mod, 'some_module')
person kurczak    schedule 27.08.2009

from foo.bar import *

это плохая практика, поскольку она импортирует some_module в глобальную область видимости.

Вы должны иметь доступ к своему модулю через:

import foo.bar
mod = getattr(foo.bar, 'some_module')

Можно легко продемонстрировать, что этот подход работает:

>>> import os.path
>>> getattr(os.path, 'basename')
<function basename at 0x00BBA468>
>>> getattr(os.path, 'basename\n')
Traceback (most recent call last):
  File "<pyshell#31>", line 1, in <module>
    getattr(os.path, 'basename\n')
AttributeError: 'module' object has no attribute 'basename
'

P.S. Если вы все еще заинтересованы в использовании своего типа оператора импорта. Вам нужен eval:

from foo.bar import *
eval('some_module')

Для уточнения: использование *-import не только является плохой практикой, но еще хуже в сочетании с eval. Так что просто используйте getattr, он создан именно для таких ситуаций, как ваша.

person SilentGhost    schedule 27.08.2009
comment
-1 за рекомендацию eval(). Всегда используйте globals()['some_module'] вместо этого, если все, что вам нужно, это найти значение в глобальной области видимости. - person Daniel Pryden; 27.08.2009
comment
Хорошо, еще раз +1 за ваше разъяснение. getattr() - правильный ответ здесь. Если вам нужно использовать __import__(), см. ответ курчака. - person Daniel Pryden; 27.08.2009
comment
О, теперь я получаю Голосование слишком старым, чтобы его можно было изменить, если только этот ответ не будет отредактирован. Мои извинения - я увидел eval() в блоке кода и автоматически нажал -1. - person Daniel Pryden; 27.08.2009
comment
извините, похоже, это не работает... при этом возникает ошибка: объект 'module' не имеет атрибута 'some_module' (не знаю, почему он относится к foo.bar как к модулю...) - person olamundo; 27.08.2009
comment
Это работает отлично, это просто означает, что foo.bar не имеет атрибута some_module. Откуда вы берете имя? - person SilentGhost; 27.08.2009
comment
он отлично работает, если вы добавите строку с getattr, упомянутую в ответе курчака - person olamundo; 29.08.2009
comment
а ты как-то пропустил ту же строчку в моем ответе? - person SilentGhost; 29.08.2009

Из документов:

Прямое использование __import__() редко, за исключением случаев, когда вы хотите импортировать модуль, имя которого известно только во время выполнения.

Однако пунктирная запись должна работать:

mod = __import__('foo.bar.some_module')
person ewall    schedule 27.08.2009