Pourquoi les modules Python n'importent-ils parfois pas leurs sous-modules?

88

J'ai remarqué quelque chose de bizarre aujourd'hui que j'aimerais expliquer. Je ne savais pas à 100% comment formuler cela comme une question, donc Google est hors de question. Le module de journalisation n'a pas accès au module logging.handlers pour une raison étrange. Essayez-le vous-même si vous ne me croyez pas:

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

Quelqu'un peut-il expliquer pourquoi cela se produit?

Chriscauley
la source

Réponses:

119

En Python, les modules doivent être importés avant d'être accessibles. import loggingimporte uniquement le module de journalisation. Il se trouve qu'il loggings'agit d'un package avec des sous-modules, mais ces sous-modules ne sont toujours pas chargés automatiquement. Vous devez donc importer explicitement logging.handlersavant de pouvoir y accéder.

Si vous vous demandez pourquoi il semble parfois que vous n'ayez pas besoin de ces importations supplémentaires: certains paquets importent tout ou partie de leurs sous-modules lorsqu'ils sont importés - simplement en effectuant ces importations dans leurs __init__.pyfichiers. Dans d'autres cas, il se peut que vous importiez quelque chose d'autre, également importé logging.handlers. Peu importe le morceau de code qui importe; tant qu'un élément de votre processus est importé logging.handlersavant que vous n'y accédiez, il sera là. Et parfois, un module qui ressemble à un package n'en est pas vraiment un, comme oset os.path. osn'est pas un package, il importe simplement l'autre module correct (pour votre plate-forme) et l'appelle path, juste pour que vous puissiez y accéder en tant que os.path.

Thomas Wouters
la source
4

Je suis également novice en python et après avoir eu beaucoup de pratique, je peux maintenant faire la différence entre, package (dossier), module (.py), classes, variables ... etc ...

si vous voulez que l'un de vos dossiers soit un package python - il doit contenir un __init__.pyfichier même un fichier vide fera l'affaire !!!

et comme Thomas l'a dit, vous pouvez importer un module supplémentaire dans __init__.py si vous le souhaitez !!! mais les modules / packages ne sont accessibles qu'après leur importation ...

si vous souhaitez tout importer à partir d'un module, vous pouvez utiliser

from logging import *

reste, vous pouvez accéder au module des gestionnaires comme ci-dessous aussi,

from logging import handlers
print dir(handlers)

shahjapan
la source
5
Veuillez ne pas utiliser from module import *. C'est presque toujours une erreur.
Thomas Wouters
Si vous voulez que tout dans un package soit importé automatiquement, effectuez ces importations dans init .py, au lieu de définir tout dans init .py et de faire 'from package import *' quelque part.
Thomas Wouters
2
@Pete: parce qu'il "pollue" l'espace de noms standard qui conduit à l'ambiguïté et au conflit. Si j'avais import zipperet zipper.open()vous sauriez exactement quelle ouverture j'appelais. Au contraire, from zipper import *suivi de open()est-ce le ouvert intégré ou zipper.open ou autre chose. import zipper as zest de zipper
loin
3
@Pete: C'est aussi un problème car vous pourriez écraser une partie de votre espace de noms sans le savoir. J'utilisais depuis numpy import *parce que certaines fonctions numpy ne fonctionnent pas à moins que vous n'importiez tous numpy (terrible défaut de conception de leur part IMO) mais numpy a un nombre ÉNORME d'objets qu'il importe. J'ai fini par écraser beaucoup de fonctions (je crois que copier en était une ... je suis trop fatigué pour vérifier). Maintenant, j'importe numpy en tant que np si je vais utiliser tellement numpy que je ne supporte pas de le taper encore et encore.
chriscauley
2
@dustynachos, quelle fonction numpy a ce défaut?
Winston Ewert
2

Thomas Wouters a très bien répondu à cette question, mais hélas, je n'ai trouvé cette question qu'après avoir trouvé la réponse dans la documentation originale. À cette fin, j'ai pensé ajouter à cela dans l'espoir que cela se rapproche du sommet du moteur de recherche à l'avenir.

QUESTION

Pourquoi l'erreur: ' AttributeError: module' module_name 'n'a pas d'attribut' sub_module_name 'apparaît même si mon éditeur (par exemple Visual Code) complète automatiquement le nom du sous-module:

 import module_name
 module_name.sub_module_name(parameter)

RÉPONDRE

Votre éditeur base sa saisie semi-automatique sur la structure de fichiers de votre projet et non sur le comportement Python. Les sous-modules ne sont pas importés «automatiquement» lorsque vous importez un module. Référence Python Documentation Pour plus de détails sur la façon de sous-modules d'importation « automatiquement » lors de l' utilisation

 import module_name

La contribution clé avec cette réponse étant l'ajout d'AttributeError lors de la tentative d'importer un 'module' ou 'package'

J'espère que cela aide quelqu'un!

Dépassement
la source
1

J'ai fait face récemment à la même situation étrange. Donc, je parie que vous avez supprimé une importation de bibliothèques tierces. Cette bibliothèque supprimée contenait from logging import handlersou from logging import *et vous fournissait handlers. Et dans un autre script, vous avez eu quelque chose comme import logginget juste utilisé logging.handlerset vous avez pensé que c'est ainsi que les choses fonctionnent comme moi.

Alexey
la source