Por que os módulos Python às vezes não importam seus submódulos?

88

Percebi algo estranho hoje que gostaria que fosse explicado. Eu não estava 100% certo de como formular isso como uma pergunta, então google está fora de questão. O módulo de registro não tem acesso ao módulo logging.handlers por algum motivo estranho. Experimente você mesmo se não acredita em mim:

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

Alguém pode explicar por que isso acontece?

Chriscauley
fonte

Respostas:

119

No Python, os módulos precisam ser importados antes de serem acessíveis. import loggingimporta apenas o módulo de registro. Acontece que loggingé um pacote com submódulos, mas esses submódulos ainda não são carregados automaticamente. Portanto, você precisa importar explicitamente logging.handlersantes de acessá-lo.

Se você está se perguntando por que parece que às vezes você não precisa dessas importações extras: alguns pacotes importam alguns ou todos os seus submódulos quando são importados - simplesmente fazendo essas importações em seus __init__.pyarquivos. Em outros casos, pode ser outra coisa que você importou, também importou logging.handlers. Não importa qual código é importado; contanto que algo em seu processo seja importado logging.handlersantes de você acessá-lo, ele estará lá. E às vezes um módulo que se parece com um pacote realmente não é um, como ose os.path. osnão é um pacote, apenas importa o outro módulo correto (para sua plataforma) e o chama path, para que você possa acessá-lo como os.path.

Thomas Wouters
fonte
4

Eu também sou novo em python e depois de ter muita prática agora posso diferenciar entre pacote (pasta), módulo (.py), classes, variáveis ​​... etc ...

se você quiser que qualquer uma das suas pastas seja um pacote python - Ele deve conter o __init__.pyarquivo, mesmo um arquivo vazio serve !!!

e como Thomas disse, você pode importar módulo extra no __init__.py se quiser !!! mas os módulos / pacotes são acessíveis apenas após importá-lo ...

se você deseja importar tudo de um módulo, você pode usar

from logging import *

resto você pode acessar o módulo de manipuladores como abaixo também,

from logging import handlers
print dir(handlers)

Shahjapan
fonte
5
Por favor, não use from module import *. Quase sempre é um erro.
Thomas Wouters
Se você quiser que tudo em um pacote seja importado automaticamente, faça essas importações em init .py, ao invés de definir tudo em init .py e fazer 'a partir de importação de pacote *' em algum lugar.
Thomas Wouters
2
@Pete: porque "polui" o namespace padrão, o que leva à ambigüidade e ao conflito. Se eu tivesse import zippere zipper.open()você soubesse exatamente para qual abertura eu estava ligando. Ao contrário, from zipper import *seguido por open()é o open embutido ou zipper.open ou qualquer outra coisa. import zipper as zé muito preferido se você se cansar de digitarzipper
msw
3
@Pete: Também é um problema porque você pode sobrescrever parte do seu namespace sem saber. Eu costumava usar o from numpy import *porque algumas funções numpy não funcionam a menos que você importe todos os numpy (falha de design terrível da parte deles, IMO), mas numpy tem um número ENORME de objetos que importa. Acabei substituindo muitas funções (acredito que cópia foi uma ... Estou cansado demais para verificar). Agora eu importo numpy como np se vou usar numpy tanto que não suporto digitá-lo indefinidamente.
chriscauley
2
@dustynachos, qual função entorpecida tem essa falha?
Winston Ewert
2

Thomas Wouters respondeu muito bem a essa pergunta, mas, infelizmente, só encontrei essa pergunta depois de encontrar a resposta na documentação original. Para esse fim, pensei em acrescentar algo na esperança de que ele apareça mais perto do topo do mecanismo de pesquisa no futuro.

QUESTÃO

Por que o erro: ' AttributeError: module' module_name 'não tem nenhum atributo' sub_module_name 'aparece, embora meu editor (por exemplo, Visual Code) preencha automaticamente o nome do submódulo:

 import module_name
 module_name.sub_module_name(parameter)

RESPONDA

Seu editor está baseando seu preenchimento automático na estrutura de arquivo do seu projeto e não no comportamento do Python. Os submódulos não são importados 'automaticamente' quando você importa um módulo. Referência Python Documentação para obter mais detalhes sobre como 'automaticamente' sub-módulos de importação quando se utiliza

 import module_name

A principal contribuição com esta resposta é a adição de AttributeError ao tentar importar um 'módulo' ou 'pacote'

Espero que isso ajude alguém!

Underflow
fonte
1

Eu enfrentei recentemente a mesma situação estranha. Então, aposto que você removeu alguma importação de lib de terceiros. Essa lib removida continha from logging import handlersou from logging import *e fornecia a você handlers. E em outro script você teve algo parecido import logginge acabou de usar logging.handlerse você pensou que é assim que as coisas funcionam como eu.

Alexey
fonte