Como já usei pacotes simples, não esperava o problema que encontrei com pacotes aninhados. Aqui está…
Layout de diretório
dir
|
+-- test.py
|
+-- package
|
+-- __init__.py
|
+-- subpackage
|
+-- __init__.py
|
+-- module.py
Conteúdo de init .py
Ambos package/__init__.py
e package/subpackage/__init__.py
estão vazios.
Conteúdo de module.py
# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...
Conteúdo de test.py
(3 versões)
Versão 1
# file test.py
from package.subpackage.module import *
print attribute1 # OK
Essa é a maneira ruim e insegura de importar coisas (importar tudo em massa), mas funciona.
Versão 2
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1
Uma maneira mais segura de importar, item por item, mas falha, o Python não quer isso: falha com a mensagem: "Nenhum módulo denominado módulo". Contudo …
# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here
… Diz <module 'package.subpackage.module' from '...'>
. Então isso é um módulo, mas não é um módulo / -P 8-O ... uh
Versão 3
# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK
Este funciona. Então você é forçado a usar o prefixo exagerado o tempo todo ou usar a forma insegura como na versão 1 e não permitida pelo Python para usar a forma prática e segura? A melhor maneira, que é segura e evita o prefixo longo desnecessário, é a única que o Python rejeita? É porque ama import *
ou porque ama prefixos longos demais (o que não ajuda a reforçar essa prática)?
Desculpe pelas palavras duras, mas já faz dois dias que estou tentando contornar esse comportamento estúpido. A menos que eu estivesse totalmente errado em algum lugar, isso me deixará com a sensação de que algo está realmente quebrado no modelo de pacote e subpacotes do Python.
Notas
- Não quero depender de
sys.path
, para evitar efeitos colaterais globais, nem de*.pth
arquivos, que são apenas outra forma de brincarsys.path
com os mesmos efeitos globais. Para que a solução seja limpa, ela deve ser apenas local. Ou o Python é capaz de lidar com subpacotes, ou não, mas não deveria ser necessário brincar com a configuração global para poder lidar com coisas locais. - Também tentei usar importações no
package/subpackage/__init__.py
, mas não resolveu nada, faz o mesmo, e reclama quesubpackage
não é um módulo conhecido, enquantoprint subpackage
diz que é um módulo (comportamento estranho, de novo).
Pode ser que eu esteja totalmente errado (a opção que eu preferiria), mas isso me deixa muito desapontado com o Python.
Alguma outra forma conhecida além das três que experimentei? Algo que eu não sei?
(suspiro)
-----% <----- editar ----->% -----
Conclusão até agora (após comentários das pessoas)
Não há nada como um subpacote real em Python, já que todas as referências de pacote vão para um dicionário global, apenas, o que significa que não há dicionário local, o que significa que não há maneira de gerenciar a referência de pacote local.
Você deve usar prefixo completo ou prefixo curto ou alias. Como em:
Versão de prefixo completo
from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)
Versão de prefixo curto (mas prefixo repetido)
from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place
Ou então, uma variação do anterior.
from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context
Versão fatorada
Se você não se importa em importar várias entidades de uma vez em um lote, pode:
from package.subpackage.module import attribute1, attribute2
# and etc.
Não está no meu primeiro gosto favorito (prefiro ter uma declaração de importação por entidade importada), mas pode ser aquela que eu pessoalmente prefiro.
Atualização (14/09/2012):
Finalmente parece estar bem na prática, exceto com um comentário sobre o layout. Em vez do acima, usei:
from package.subpackage.module import (
attribute1,
attribute2,
attribute3,
...) # and etc.