Почему модули Python иногда не импортируют свои подмодули?

88

Сегодня я заметил кое-что странное и хотел бы объяснить. Я не был на 100% уверен, как сформулировать это как вопрос, поэтому о Google не может быть и речи. Модуль logging по какой-то странной причине не имеет доступа к модулю logging.handlers. Попробуйте сами, если не верите:

>>> import logging
>>> logging.handlers
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'handlers'
>>> import logging.handlers
>>> logging.handlers
<module 'logging.handlers' from '/usr/lib/python2.6/logging/handlers.pyc'>

Кто-нибудь может объяснить, почему это происходит?

Крисколи
источник

Ответы:

119

В Python модули необходимо импортировать, прежде чем они станут доступными. import loggingимпортирует только модуль регистрации. Так получилось, что loggingэто пакет с подмодулями, но эти подмодули по-прежнему не загружаются автоматически. Итак, вам нужно явно импортировать, logging.handlersпрежде чем вы сможете получить к нему доступ.

Если вам интересно, почему иногда кажется, что вам не нужен этот дополнительный импорт: некоторые пакеты импортируют некоторые или все свои подмодули при импорте - просто выполняя этот импорт в своих __init__.pyфайлах. В других случаях это может быть что-то еще, что вы импортируете, также импортировано logging.handlers. Неважно, какой фрагмент кода выполняет импорт; пока что- то в вашем процессе импортируется logging.handlersдо того, как вы получите к нему доступ, оно будет там. И иногда модуль, который выглядит как пакет, на самом деле не является таковым, как osи os.path. osне является пакетом, он просто импортирует другой правильный модуль (для вашей платформы) и вызывает его path, чтобы вы могли получить к нему доступ как os.path.

Томас Воутерс
источник
4

Я также новичок в python, и после большой практики теперь я могу различать пакет (папка), модуль (.py), классы, переменные ... и т. Д.

если вы хотите, чтобы любая из ваших папок была пакетом python - он должен содержать __init__.pyфайл, даже пустой файл будет делать !!!

и, как сказал Томас, вы можете импортировать дополнительный модуль в __init__.p y, если хотите !!! но модули / пакеты доступны только после их импорта ...

если вы хотите импортировать все из модуля, вы можете использовать

from logging import *

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

from logging import handlers
print dir(handlers)

Шахджапан
источник
5
Пожалуйста, не используйте from module import *. Это почти всегда ошибка.
Томас Воутерс,
Если вы хотите, чтобы все в пакете импортировалось автоматически, сделайте этот импорт в init .py, вместо того, чтобы устанавливать все в init .py и делать где-нибудь 'from package import *'.
Томас Воутерс,
2
@Pete: потому что он «загрязняет» стандартное пространство имен, что приводит к двусмысленности и конфликтам. Если бы у меня было, import zipperи zipper.open()вы бы точно знали, в какую опцию я звонил. Наоборот, from zipper import *следует open()ли это встроенный открытый или застежка-молния, или что-то еще. import zipper as zгораздо предпочтительнее, если вы устали печататьzipper
msw
3
@Pete: Это также проблема, потому что вы можете неосознанно перезаписать часть своего пространства имен. Раньше я использовал from, numpy import *потому что некоторые функции numpy не работают, если вы не импортируете все numpy (ужасный недостаток дизайна с их стороны IMO), но numpy имеет ОГРОМНОЕ количество объектов, которые он импортирует. Я закончил тем, что перезаписал множество функций (я считаю, что копия была одной ... Я слишком устал, чтобы проверять). Теперь я действительно импортирую numpy как np, если я собираюсь использовать numpy так много, что не могу печатать его снова и снова.
Крискоули,
2
@dustynachos, у какой функции numpy есть этот недостаток?
Winston Ewert
2

Томас Воутерс очень хорошо ответил на этот вопрос, но, увы, я нашел этот вопрос только после того, как нашел ответ в исходной документации. С этой целью я подумал, что добавлю к этому в надежде, что в будущем он станет ближе к вершине поисковой системы.

ВОПРОС

Почему появляется ошибка: ' AttributeError: module' module_name 'не имеет атрибута' sub_module_name ', хотя мой редактор (например, Visual Code) автоматически завершает имя подмодуля:

 import module_name
 module_name.sub_module_name(parameter)

ОТВЕТ

Ваш редактор основывает свое автозаполнение на файловой структуре вашего проекта, а не на поведении Python. Подмодули не импортируются «автоматически» при импорте модуля. Справочная документация Python для получения подробной информации о том, как «автоматически» импортировать подмодули при использовании

 import module_name

Ключевым вкладом в этот ответ является добавление AttributeError при попытке импортировать «модуль» или «пакет».

Надеюсь, это кому-то поможет!

Недополнение
источник
1

Недавно я столкнулся с такой же странной ситуацией. Итак, держу пари, вы удалили импорт некоторых сторонних библиотек. Эта удаленная библиотека содержала from logging import handlersили from logging import *предоставила вам handlers. А в другом сценарии у вас было что-то вроде, import loggingи вы только что использовали, logging.handlersи вы думали, что все работает так же, как и я.

Алексей
источник