Модуль Python не определен в модуле при использовании пользовательской функции загрузки
Рассмотрим следующую программу для загрузки всех модулей в каталоге:
import pkgutil
import os.path
import sys
def load_all(directory):
for loader, name, ispkg in pkgutil.walk_packages([directory]):
loader.find_module(name).load_module(name)
if __name__ == '__main__':
here = os.path.dirname(os.path.realpath(__file__))
path = os.path.join(here, 'lib')
sys.path.append(path)
load_all(path)
Теперь рассмотрим, что у нас есть следующие файлы.
Библиотека / магия / imho.py:
"""This is an empty module.
"""
Библиотека / магия / wtf.py:
import magic.imho
print "magic contents:", dir(magic)
Библиотека / магия / __ init__.py:
"Empty package init file"
При выполнении программы выше, это выдает:
magic contents: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__']
Другими словами, несмотря наimport magic.imho
нет атрибутаimho
на упаковкеmagic
что вызывает любые последующие ссылки наmagic.imho
терпеть неудачу.
Запуск одного и того же кода (более или менее) непосредственно в python показывает другой вывод, который я ожидал от запуска программы загрузки.
$ PYTHONPATH=lib ipython
Python 2.7.6 (default, Mar 22 2014, 22:59:38)
Type "copyright", "credits" or "license" for more information.
IPython 1.2.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: import magic.wtf
magic contents: ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'imho']
Почему есть разница?
Обновить: Дело в том, что символmagic.imho
не существует внутриmagic.wft
несмотря на то, что он был явно импортирован. Итак, что нужно сделать с пользовательской процедурой загрузки, чтобы она работала правильно и чтобы символявляется видимый после того, как он был импортирован вmagic.wtf
.
Решение с использованиемsetattr
: BartoszKP дал решение ниже, используяexec
назначить значение для пакета. Так как я обычно не люблю использоватьexec
(по многим причинам инъекции являются первыми) я использовалsetattr
а такжеrpartition
следующее:
def load_all(directory):
for loader, name, ispkg in pkgutil.walk_packages([directory]):
module = loader.find_module(name).load_module(name)
pkg_name, _, mod_name = name.rpartition('.')
if pkg_name:
setattr(sys.modules[pkg], mod_name, module)