¿Por qué los módulos de Python a veces no importan sus submódulos?

88

Hoy noté algo extraño que me gustaría que me explicaran. No estaba 100% seguro de cómo expresar esto como una pregunta, por lo que Google está fuera de discusión. El módulo de registro no tiene acceso al módulo logging.handlers por alguna extraña razón. Pruébelo usted mismo si no me cree:

>>> 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'>

¿Alguien puede explicar por qué sucede esto?

Chriscauley
fuente

Respuestas:

119

En Python, los módulos deben importarse antes de que sean accesibles. import loggingimporta solo el módulo de registro. Da la casualidad de que logginges un paquete con submódulos, pero esos submódulos todavía no se cargan automáticamente. Por lo tanto, debe importar explícitamente logging.handlersantes de poder acceder a él.

Si se pregunta por qué parece que a veces no necesita esas importaciones adicionales: algunos paquetes importan algunos o todos sus submódulos cuando se importan, simplemente haciendo esas importaciones en sus __init__.pyarchivos. En otros casos, podría ser otra cosa que importa, también importa logging.handlers. No importa qué fragmento de código se importe; siempre que algo en su proceso se importe logging.handlersantes de acceder a él, estará allí. Y a veces, un módulo que parece un paquete realmente no lo es, como osy os.path. osno es un paquete, simplemente importa el otro módulo correcto (para su plataforma) y lo llama path, solo para que pueda acceder a él como os.path.

Thomas Wouters
fuente
4

También soy nuevo en Python y después de tener mucha práctica ahora puedo diferenciar entre, paquete (carpeta), módulo (.py), clases, variables ... etc ...

si desea que alguna de sus carpetas sea un paquete de python, debe contener un __init__.pyarchivo, incluso un archivo vacío servirá.

y como dijo Thomas, ¡puedes importar módulo adicional en __init__.py si quieres! pero los módulos / paquetes son accesibles solo después de importarlos ...

si desea importar todo desde un módulo, puede usar

from logging import *

resto, también puede acceder al módulo de controladores como se muestra a continuación,

from logging import handlers
print dir(handlers)

shahjapan
fuente
5
Por favor no lo use from module import *. Casi siempre es un error.
Thomas Wouters
Si desea que todo en un paquete se importe automáticamente, haga esas importaciones en init .py, en lugar de configurar todo en init .py y hacer 'from package import *' en alguna parte.
Thomas Wouters
2
@Pete: porque "contamina" el espacio de nombres estándar, lo que genera ambigüedad y conflicto. Si lo hubiera hecho import zippery zipper.open()sabrías exactamente a qué abierto estaba llamando. A la inversa, from zipper import *seguido de open()la apertura incorporada o la cremallera, la apertura o algo más. import zipper as zes mucho más preferido si se cansa de escribirzipper
msw
3
@Pete: También es un problema porque podrías sobrescribir parte de tu espacio de nombres sin saberlo. Solía ​​usar from numpy import *porque algunas funciones numpy no funcionan a menos que importe todo numpy (un terrible defecto de diseño por su parte, en mi opinión), pero numpy tiene una gran cantidad de objetos que importa. Terminé sobrescribiendo muchas funciones (creo que la copia fue una ... Estoy demasiado cansado para verificar). Ahora importo numpy como np si voy a usar tanto numpy que no puedo soportar escribirlo una y otra vez.
chriscauley
2
@dustynachos, ¿qué función numpy tiene ese defecto?
Winston Ewert
2

Thomas Wouters respondió muy bien a esta pregunta, pero, lamentablemente, solo encontré esta pregunta después de encontrar la respuesta en la documentación original. Con ese fin, pensé en agregar a esto con la esperanza de que aparezca más cerca de la parte superior del motor de búsqueda en el futuro.

PREGUNTA

Por qué aparece el error: ' AttributeError: module' module_name 'no tiene atributo' sub_module_name 'aunque mi editor (por ejemplo, Visual Code) completa automáticamente el nombre del submódulo:

 import module_name
 module_name.sub_module_name(parameter)

RESPONDER

Su editor basa su autocompletado en la estructura de archivos de su proyecto y no en el comportamiento de Python. Los submódulos no se importan "automáticamente" cuando se importa un módulo. Referencia de documentación de Python para obtener más información sobre cómo 'automáticamente' importación submódulos al utilizar

 import module_name

La contribución clave con esta respuesta es la adición de AttributeError al intentar importar un 'módulo' o 'paquete'

¡Espero que esto ayude a alguien!

Desbordamiento
fuente
1

Recientemente me he enfrentado a la misma situación extraña. Entonces, apuesto a que ha eliminado alguna importación de lib de terceros. Eso eliminó lib contenido from logging import handlerso from logging import *y le proporcionó handlers. Y en otro guión has tenido algo así import loggingy logging.handlerslo has usado y has pensado que es una forma en que las cosas funcionan como yo.

Alexey
fuente