Eu estive aqui:
- http://www.python.org/dev/peps/pep-0328/
- http://docs.python.org/2/tutorial/modules.html#packages
- Pacotes Python: importações relativas
- código de exemplo de importação relativa do python não funciona
- Resposta definitiva às importações relativas de python
- Importações relativas em Python
- Python: desativando a importação relativa
e muitos URLs que eu não copiei, alguns no SO, outros em outros sites, quando pensei que teria a solução rapidamente.
A pergunta sempre recorrente é a seguinte: Com o Windows 7, Python 2.7.3 de 32 bits, como soluciono a mensagem "Tentativa de importação relativa em pacote não"? Criei uma réplica exata do pacote no pep-0328:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
As importações foram feitas no console.
Eu criei funções nomeadas spam e eggs em seus módulos apropriados. Naturalmente, não funcionou. Aparentemente, a resposta está no quarto URL que listei, mas são todos os ex-alunos para mim. Houve esta resposta em um dos URLs que visitei:
As importações relativas usam o atributo de nome de um módulo para determinar a posição desse módulo na hierarquia de pacotes. Se o nome do módulo não contiver nenhuma informação do pacote (por exemplo, está definido como 'main'), as importações relativas serão resolvidas como se o módulo fosse um módulo de nível superior, independentemente de onde o módulo esteja realmente localizado no sistema de arquivos.
A resposta acima parece promissora, mas são todos hieróglifos para mim. Então, minha pergunta: como faço para que o Python não retorne para mim "Tentativa de importação relativa em não pacote"? tem uma resposta que envolve -m, supostamente.
Alguém pode me dizer por que o Python transmite essa mensagem de erro, o que significa "não-pacote", por que e como você define um 'pacote', e a resposta precisa colocada em termos fáceis o suficiente para que um jardim de infância entenda .
fonte
def spam(): pass
, moduleA.py hasdef eggs(): pass
. Tentei executar alguns comandos "de .algo importar algo", mas eles não funcionaram. Novamente, consulte pep-0328.from .something import something
no intérprete interativo, isso não funcionará. As importações relativas só podem ser usadas dentro de módulos, não interativamente.Respostas:
Script vs. Módulo
Aqui está uma explicação. A versão curta é que há uma grande diferença entre executar diretamente um arquivo Python e importá-lo de outro lugar. Apenas saber em que diretório um arquivo está não determina em que pacote o Python pensa que está. Isso depende, adicionalmente, de como você carrega o arquivo no Python (executando ou importando).
Existem duas maneiras de carregar um arquivo Python: como o script de nível superior ou como um módulo. Um arquivo é carregado como o script de nível superior se você o executar diretamente, por exemplo, digitando
python myfile.py
na linha de comando. Ele é carregado como um módulo, se você o fizerpython -m myfile
, ou se for carregado quando umaimport
instrução for encontrada dentro de outro arquivo. Só pode haver um script de nível superior por vez; o script de nível superior é o arquivo Python que você executou para começar.Nomeação
Quando um arquivo é carregado, ele recebe um nome (que é armazenado em seu
__name__
atributo). Se ele foi carregado como o script de nível superior, seu nome é__main__
. Se ele foi carregado como um módulo, seu nome é o nome do arquivo, precedido pelos nomes de quaisquer pacotes / subpacotes dos quais faz parte, separados por pontos.Por exemplo, no seu exemplo:
se você importou
moduleX
(nota: importado , não executado diretamente), seu nome seriapackage.subpackage1.moduleX
. Se você importassemoduleA
, seu nome seriapackage.moduleA
. No entanto, se você executar diretamentemoduleX
na linha de comando, seu nome será__main__
e, se você executar diretamentemoduleA
na linha de comando, o nome será__main__
. Quando um módulo é executado como o script de nível superior, ele perde seu nome normal e seu nome é__main__
.Acessando um módulo NÃO através do pacote que o contém
Há uma ruga adicional: o nome do módulo depende se foi importado "diretamente" do diretório em que está ou se foi importado por meio de um pacote. Isso só faz diferença se você executar o Python em um diretório e tentar importar um arquivo no mesmo diretório (ou em um subdiretório). Por exemplo, se você iniciar o interpretador Python no diretório
package/subpackage1
e o fizerimport moduleX
, o nome demoduleX
apenas serámoduleX
, e nãopackage.subpackage1.moduleX
. Isso ocorre porque o Python adiciona o diretório atual ao seu caminho de pesquisa na inicialização; se encontrar o módulo a ser importado no diretório atual, ele não saberá que esse diretório faz parte de um pacote e as informações do pacote não se tornarão parte do nome do módulo.Um caso especial é se você executar o interpretador interativamente (por exemplo, basta digitar
python
e começar a digitar o código Python em tempo real). Nesse caso, o nome dessa sessão interativa é__main__
.Agora, aqui está a coisa crucial para sua mensagem de erro: se o nome de um módulo não tiver pontos, ele não será considerado parte de um pacote . Não importa onde o arquivo está no disco. Tudo o que importa é qual é o nome e depende de como você o carregou.
Agora observe a citação que você incluiu na sua pergunta:
Importações relativas ...
As importações relativas usam o nome do módulo para determinar onde ele está em um pacote. Quando você usa uma importação relativa como
from .. import foo
, os pontos indicam para aumentar um número de níveis na hierarquia de pacotes. Por exemplo, se o nome do seu módulo atual forpackage.subpackage1.moduleX
,..moduleA
isso significariapackage.moduleA
. Para que umfrom .. import
trabalho funcione, o nome do módulo deve ter pelo menos quantos pontos houver naimport
instrução.... são apenas relativos em um pacote
No entanto, se o nome do seu módulo for
__main__
, ele não será considerado em um pacote. Seu nome não tem pontos e, portanto, você não pode usarfrom .. import
instruções dentro dele. Se você tentar fazer isso, receberá o erro "importação relativa no pacote".Os scripts não podem importar relativos
O que você provavelmente fez foi tentar executar algo
moduleX
semelhante na linha de comando. Quando você fez isso, seu nome foi definido como__main__
, o que significa que as importações relativas falharão, porque seu nome não revela que está em um pacote. Observe que isso também acontecerá se você executar o Python a partir do mesmo diretório em que um módulo está e tentar importar esse módulo, porque, conforme descrito acima, o Python encontrará o módulo no diretório atual "muito cedo" sem perceber que é parte de um pacote.Lembre-se também de que, quando você executa o intérprete interativo, o "nome" dessa sessão interativa é sempre
__main__
. Portanto, você não pode fazer importações relativas diretamente de uma sessão interativa . As importações relativas são apenas para uso nos arquivos do módulo.Duas soluções:
Se você realmente deseja executar
moduleX
diretamente, mas ainda assim ele é considerado parte de um pacote, é possívelpython -m package.subpackage1.moduleX
. O-m
comando diz ao Python para carregá-lo como um módulo, não como o script de nível superior.Ou talvez você realmente não queira executar
moduleX
, apenas deseja executar outro script, digamosmyfile.py
, que use funções internasmoduleX
. Se for esse o caso, coloquemyfile.py
em outro lugar - não dentro dopackage
diretório - e execute-o. Se dentro demyfile.py
você fizer coisas comofrom package.moduleA import spam
, vai funcionar bem.Notas
Para qualquer uma dessas soluções, o diretório do pacote (
package
no seu exemplo) deve estar acessível no caminho de pesquisa do módulo Python (sys.path
). Caso contrário, você não poderá usar nada no pacote de maneira confiável.Desde o Python 2.6, o "nome" do módulo para fins de resolução de pacotes é determinado não apenas por seus
__name__
atributos, mas também pelo__package__
atributo. É por isso que evito usar o símbolo explícito__name__
para me referir ao "nome" do módulo. Desde o Python 2.6, o "nome" de um módulo é eficaz__package__ + '.' + __name__
, ou apenas__name__
se__package__
forNone
.)fonte
Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.
Isso é fundamentalmente perturbador. O que há de tão difícil em olhar para o diretório atual? Python deve ser capaz disso. Isso está corrigido na versão 3x?__package__ = 'package.subpackage1'
ou algo parecido. Então que arquivo só irá sempre ser considerado parte desse pacote, mesmo se executado diretamente. Se você tiver outras perguntas,__package__
faça uma pergunta separada, pois estamos saindo do problema de sua pergunta original aqui.__name__
esys.path
. Especificamente, compython -m pkg.mod
,__name__
está definido como__main__
, nãopkg.mod
; as importações relativas são resolvidas usando,__package__
e não__name__
neste caso. Além disso, o Python adiciona o diretório do script ao invés do diretório atual aosys.path
executarpython path/to/script.py
; ele adiciona o diretório atual aosys.path
executar a maioria das outras maneiras, inclusivepython -m pkg.mod
.Este é realmente um problema dentro do python. A origem da confusão é que as pessoas assumem erroneamente a importação relativa como caminho relativo que não é.
Por exemplo, quando você escreve em faa.py :
Isso só tem significado se o faa.py foi identificado e carregado pelo python, durante a execução, como parte de um pacote. Nesse caso, o nome do módulo para faa.py seria, por exemplo, some_packagename.faa . Se o arquivo foi carregado apenas porque está no diretório atual, quando o python é executado, seu nome não se refere a nenhum pacote e, eventualmente, a importação relativa falhará.
Uma solução simples para referenciar módulos no diretório atual é usar o seguinte:
fonte
from __future__ import absolute_import
e forçar o usuário a usar seu código corretamente ... de modo que você sempre pode fazerfrom . import foo
Aqui está uma receita geral, modificada para caber como exemplo, que eu estou usando agora para lidar com bibliotecas Python escritas como pacotes, que contêm arquivos interdependentes, onde eu quero poder testar partes delas em partes. Vamos chamar isso
lib.foo
e dizer que ele precisa acessarlib.fileA
para funçõesf1
ef2
, elib.fileB
para classeClass3
.Incluí algumas
print
chamadas para ajudar a ilustrar como isso funciona. Na prática, você deseja removê-los (e talvez também afrom __future__ import print_function
linha).Este exemplo em particular é muito simples para mostrar quando realmente precisamos inserir uma entrada
sys.path
. (Veja a resposta Lars' para um caso em que não precisa dele, quando temos dois ou mais níveis de diretórios do pacote, e então usamosos.path.dirname(os.path.dirname(__file__))
-mas ele realmente não se machucar aqui também.) Também é seguro o suficiente para fazer isso sem aif _i in sys.path
teste. No entanto, se cada arquivo importado inserir o mesmo caminho - por exemplo, se os doisfileA
efileB
quiser importar utilitários do pacote - isso se confundesys.path
com o mesmo caminho muitas vezes, então é bom ter issoif _i not in sys.path
no padrão.A idéia aqui é essa (e observe que tudo isso funciona da mesma maneira no python2.7 e python 3.x):
Se executado como
import lib
oufrom lib import foo
como uma importação regular de pacotes do código comum,__package
élib
e__name__
élib.foo
. Pegamos o primeiro caminho do código, importando de.fileA
etc.Se executar como
python lib/foo.py
,__package__
será Nenhum e__name__
será__main__
.Pegamos o segundo caminho do código. O
lib
diretório já estará no diretóriosys.path
e não será necessário adicioná-lo. Nós importamos defileA
, etc.Se executado dentro do
lib
diretório comopython foo.py
, o comportamento é o mesmo do caso 2.Se executado dentro do
lib
diretório comopython -m foo
, o comportamento é semelhante aos casos 2 e 3. No entanto, o caminho para olib
diretório não estásys.path
, portanto, nós o adicionamos antes da importação. O mesmo se aplica se rodarmos Python e depoisimport foo
.(Uma vez que
.
é nosys.path
, nós realmente não precisa adicionar a versão absoluta do caminho aqui. Este é o lugar onde uma estrutura de aninhamento pacote mais profundo, onde queremos fazerfrom ..otherlib.fileC import ...
, faz a diferença. Se você não está fazendo isso, você pode omita toda asys.path
manipulação.)Notas
Ainda há uma peculiaridade. Se você executar tudo isso de fora:
ou:
o comportamento depende do conteúdo de
lib/__init__.py
. Se isso existe e está vazio , tudo está bem:Mas se
lib/__init__.py
ele importaroutine
para que possa exportarroutine.name
diretamente comolib.name
, você obtém:Ou seja, o módulo é importado duas vezes, uma vez através do pacote e, em seguida, novamente,
__main__
para que ele execute seumain
código. O Python 3.6 e posterior alertam sobre isso:O aviso é novo, mas o comportamento alertado não é. Faz parte do que alguns chamam de armadilha dupla de importação . (Para detalhes adicionais, consulte a edição 27487. ) Nick Coghlan diz:
Observe que, embora violemos essa regra aqui, fazemos isso apenas quando o arquivo que está sendo carregado não está sendo carregado como parte de um pacote, e nossa modificação foi projetada especificamente para permitir o acesso a outros arquivos nesse pacote. (E, como observei, provavelmente não devemos fazer isso em pacotes de nível único.) Se quisermos ser extra-limpos, poderemos reescrever isso como, por exemplo:
Ou seja, modificamos o
sys.path
tempo suficiente para alcançar nossas importações e, em seguida, colocamos de volta do jeito que era (excluindo uma cópia de_i
se e somente se adicionamos uma cópia de_i
).fonte
Então, depois de me preocupar com isso, além de muitos outros, deparei-me com uma nota postada por Dorian B neste artigo que resolveu o problema específico que eu estava tendo, onde desenvolvia módulos e classes para uso com um serviço da Web, mas também quero ser capaz de testá-los enquanto codifico, usando os recursos do depurador no PyCharm. Para executar testes em uma classe independente, incluiria o seguinte no final do meu arquivo de classe:
mas se eu quisesse importar outras classes ou módulos na mesma pasta, teria que alterar todas as minhas instruções de importação de notação relativa para referências locais (por exemplo, remover o ponto (.)). Mas, depois de ler a sugestão de Dorian, tentei a opção " one-liner 'e funcionou! Agora posso testar em PyCharm e deixar meu código de teste no lugar quando uso a classe em outra classe em teste ou quando o uso no meu serviço da Web!
A instrução if verifica se estamos executando este módulo como principal ou se está sendo usado em outro módulo que está sendo testado como principal . Talvez isso seja óbvio, mas ofereço esta observação aqui, caso alguém mais frustrado pelos problemas relativos de importação acima possa fazer uso dela.
fonte
Aqui está uma solução que eu não recomendaria, mas pode ser útil em algumas situações em que os módulos simplesmente não foram gerados:
fonte
Eu tive um problema semelhante em que não queria alterar o caminho de pesquisa do módulo Python e precisava carregar um módulo relativamente a partir de um script (apesar de "os scripts não poderem importar em relação a todos", como o BrenBarn explicou bem acima).
Então eu usei o seguinte hack. Infelizmente, ele conta com o
imp
módulo que foi descontinuado desde a versão 3.4 para ser descartado a favorimportlib
. (Isso também é possívelimportlib
? Não sei.) Ainda assim, o hack funciona por enquanto.Exemplo para acessar membros de
moduleX
in asubpackage1
partir de um script que reside nasubpackage2
pasta:Uma abordagem mais limpa parece ser modificar o sys.path usado para carregar os módulos, conforme mencionado por Federico.
fonte
__name__
muda dependendo se o código em questão é executado no espaço para nome global ou como parte de um módulo importado.Se o código não estiver em execução no espaço global,
__name__
será o nome do módulo. Se estiver em execução no espaço de nomes global - por exemplo, se você o digitar em um console ou executar o módulo como um script usandopython.exe yourscriptnamehere.py
,__name__
torna - se"__main__"
.Você verá que muitos códigos python
if __name__ == '__main__'
são usados para testar se o código está sendo executado no namespace global - que permite que você tenha um módulo que funciona como um script.Você tentou fazer essas importações do console?
fonte
A resposta da @ BrenBarn diz tudo, mas se você é como eu, pode demorar um pouco para entender. Aqui está o meu caso e como a resposta do @ BrenBarn se aplica a ele, talvez ele o ajude.
O caso
Usando nosso exemplo familiar, e adicione a ele que moduleX.py tenha uma importação relativa para ..moduleA. Dado que tentei escrever um script de teste no diretório subpackage1 que importou o moduleX, mas obtive o temido erro descrito pelo OP.
Solução
Mova o script de teste para o mesmo nível do pacote e importe package.subpackage1.moduleX
Explicação
Conforme explicado, as importações relativas são feitas em relação ao nome atual. Quando meu script de teste importa moduleX do mesmo diretório, o nome do módulo dentro de moduleX é moduleX. Quando encontra uma importação relativa, o intérprete não pode fazer backup da hierarquia de pacotes porque já está no topo
Quando importo o moduleX de cima, o nome dentro do moduleX é package.subpackage1.moduleX e a importação relativa pode ser encontrada
fonte
Escreveu um pequeno pacote python no PyPi que pode ajudar os espectadores desta pergunta. O pacote age como solução alternativa, se alguém deseja executar arquivos python contendo importações que contêm pacotes de nível superior de dentro de um pacote / projeto sem estar diretamente no diretório do arquivo de importação. https://pypi.org/project/import-anywhere/
fonte
Para fazer com que o Python não retorne para mim "Tentativa de importação relativa no pacote". pacote/
o init .py subpackage1 / o init .py moduleX.py moduleY.py subpackage2 / o init .py moduleZ.py moduleA.py
Este erro ocorre apenas se você estiver aplicando importação relativa ao arquivo pai. Por exemplo, o arquivo pai já retorna main depois que você codifica "print ( name )" em moduleA.py .so Este arquivo já é mainele não pode retornar nenhum pacote pai adiante. importações relativas são necessárias nos arquivos dos pacotes subpacote1 e subpacote2, você pode usar ".." para se referir ao diretório ou módulo pai. Mas pai é que, se já for um pacote de nível superior, ele não poderá ir além desse diretório (pacote). Esses arquivos nos quais você está aplicando importação relativa aos pais podem funcionar apenas com o aplicativo de importação absoluta. Se você usar a IMPORTAÇÃO ABSOLUTA NO PACOTE DOS PAIS, nenhum erro ocorrerá, pois o python sabe quem está no nível superior do pacote, mesmo que seu arquivo esteja em subpacotes devido ao conceito de PYTHON PATH, que define o nível superior do projeto
fonte