Importações relativas pela bilionésima vez

716

Eu estive aqui:

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 .

Paul Roub
fonte
5
Como você está tentando usar os arquivos que mostra? Qual é o código que você está executando?
BrenBarn #
Veja python.org/dev/peps/pep-0328 . Eu usei o formato do pacote que descrevi na minha postagem. Os arquivos init .py estão vazios. moduleY.py has def spam(): pass, moduleA.py has def eggs(): pass. Tentei executar alguns comandos "de .algo importar algo", mas eles não funcionaram. Novamente, consulte pep-0328.
6
Veja minha resposta. Você ainda não esclareceu completamente o que está fazendo, mas se estiver tentando fazer from .something import somethingno intérprete interativo, isso não funcionará. As importações relativas só podem ser usadas dentro de módulos, não interativamente.
BrenBarn #
105
O mero fato de que "bilhões" de pessoas - ok 83.136 a partir deste comentário - estão tendo dificuldade suficiente com as importações para pesquisar esta questão; só podemos concluir que as importações de python são contra-intuitivas para muitos, senão para a maioria dos programadores. Guido, talvez você deva aceitar isso e solicitar um comitê para redesenhar o mecanismo de importação. No mínimo, essa sintaxe deve funcionar se x.py e z.py estiverem no mesmo diretório. Ou seja, se x.py possui a instrução "from .z import MyZebraClass" x deve importar z, mesmo que esteja sendo executado como principal ! por que isso é tão difícil?
Steve L
4
Depois de ler muito deste segmento, embora não seja uma resposta para a pergunta, "é só usar importações absolutas" parece ser a solução ...
CodeJockey

Respostas:

1043

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.pyna linha de comando. Ele é carregado como um módulo, se você o fizer python -m myfile, ou se for carregado quando uma importinstruçã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:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

se você importou moduleX(nota: importado , não executado diretamente), seu nome seria package.subpackage1.moduleX. Se você importasse moduleA, seu nome seria package.moduleA. No entanto, se você executar diretamente moduleX na linha de comando, seu nome será __main__e, se você executar diretamente moduleAna 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/subpackage1e o fizer import moduleX, o nome de moduleXapenas será moduleX, e não package.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 pythone 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:

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.

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 for package.subpackage1.moduleX, ..moduleAisso significaria package.moduleA. Para que um from .. importtrabalho funcione, o nome do módulo deve ter pelo menos quantos pontos houver na importinstruçã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 usar from .. importinstruçõ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 moduleXsemelhante 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:

  1. Se você realmente deseja executar moduleXdiretamente, mas ainda assim ele é considerado parte de um pacote, é possível python -m package.subpackage1.moduleX. O -mcomando diz ao Python para carregá-lo como um módulo, não como o script de nível superior.

  2. Ou talvez você realmente não queira executar moduleX , apenas deseja executar outro script, digamos myfile.py, que use funções internas moduleX. Se for esse o caso, coloque myfile.py em outro lugar - não dentro do packagediretório - e execute-o. Se dentro de myfile.pyvocê fizer coisas como from package.moduleA import spam, vai funcionar bem.

Notas

  • Para qualquer uma dessas soluções, o diretório do pacote ( packageno 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__for None.)

BrenBarn
fonte
62
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?
7
@Stopforgettingmyaccounts ...: PEP 366 mostra como isso funciona. Dentro de um arquivo, você pode fazer __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.
BrenBarn 3/13/13
108
Essa deve ser a resposta para todas as perguntas de importação relativa do Python. Isso deve estar nos documentos, até.
Edsioufi
10
Veja python.org/dev/peps/pep-0366 - "Observe que este padrão é suficiente apenas se o pacote de nível superior já estiver acessível via sys.path. Código adicional que manipula o sys.path seria necessário para a execução direta funcionar sem que o pacote de nível superior já seja importável ". - esta é a parte mais perturbadora para mim, pois esse "código adicional" é realmente bastante longo e não pode ser armazenado em outro lugar no pacote para ser executado facilmente.
Michael Scott Cuthbert
14
Atualmente, esta resposta está desativada em alguns detalhes importantes sobre __name__e sys.path. Especificamente, com python -m pkg.mod, __name__está definido como __main__, não pkg.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 ao sys.pathexecutar python path/to/script.py; ele adiciona o diretório atual ao sys.pathexecutar a maioria das outras maneiras, inclusive python -m pkg.mod.
User2357112 suporta Monica
42

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 :

from .. import foo

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:

if __package__ is None or __package__ == '':
    # uses current directory visibility
    import foo
else:
    # uses current package visibility
    from . import foo
Rami Ka.
fonte
6
A solução correta é from __future__ import absolute_importe forçar o usuário a usar seu código corretamente ... de modo que você sempre pode fazerfrom . import foo
Giacomo Alzetta
@ Giacomo: a resposta absolutamente certa para o meu problema. Obrigado!
Fábio
8

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.fooe dizer que ele precisa acessar lib.fileApara funções f1e f2, e lib.fileBpara classe Class3.

Incluí algumas printchamadas para ajudar a ilustrar como isso funciona. Na prática, você deseja removê-los (e talvez também a from __future__ import print_functionlinha).

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 usamos os.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 a if _i in sys.pathteste. No entanto, se cada arquivo importado inserir o mesmo caminho - por exemplo, se os dois fileAe fileBquiser importar utilitários do pacote - isso se confunde sys.pathcom o mesmo caminho muitas vezes, então é bom ter isso if _i not in sys.pathno padrão.

from __future__ import print_function # only when showing how this works

if __package__:
    print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
    from .fileA import f1, f2
    from .fileB import Class3
else:
    print('Not a package; __name__ is {!r}'.format(__name__))
    # these next steps should be used only with care and if needed
    # (remove the sys.path manipulation for simple cases!)
    import os, sys
    _i = os.path.dirname(os.path.abspath(__file__))
    if _i not in sys.path:
        print('inserting {!r} into sys.path'.format(_i))
        sys.path.insert(0, _i)
    else:
        print('{!r} is already in sys.path'.format(_i))
    del _i # clean up global name space

    from fileA import f1, f2
    from fileB import Class3

... all the code as usual ...

if __name__ == '__main__':
    import doctest, sys
    ret = doctest.testmod()
    sys.exit(0 if ret.failed == 0 else 1)

A idéia aqui é essa (e observe que tudo isso funciona da mesma maneira no python2.7 e python 3.x):

  1. Se executado como import libou from lib import foocomo uma importação regular de pacotes do código comum, __packageé libe __name__é lib.foo. Pegamos o primeiro caminho do código, importando de .fileAetc.

  2. Se executar como python lib/foo.py, __package__será Nenhum e __name__será __main__.

    Pegamos o segundo caminho do código. O libdiretório já estará no diretório sys.pathe não será necessário adicioná-lo. Nós importamos de fileA, etc.

  3. Se executado dentro do libdiretório como python foo.py, o comportamento é o mesmo do caso 2.

  4. Se executado dentro do libdiretório como python -m foo, o comportamento é semelhante aos casos 2 e 3. No entanto, o caminho para o libdiretório não está sys.path, portanto, nós o adicionamos antes da importação. O mesmo se aplica se rodarmos Python e depois import foo.

    (Uma vez que . é no sys.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 fazer from ..otherlib.fileC import ..., faz a diferença. Se você não está fazendo isso, você pode omita toda a sys.pathmanipulação.)

Notas

Ainda há uma peculiaridade. Se você executar tudo isso de fora:

$ python2 lib.foo

ou:

$ python3 lib.foo

o comportamento depende do conteúdo de lib/__init__.py. Se isso existe e está vazio , tudo está bem:

Package named 'lib'; __name__ is '__main__'

Mas se lib/__init__.py ele importa routinepara que possa exportar routine.namediretamente como lib.name, você obtém:

$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'

Ou seja, o módulo é importado duas vezes, uma vez através do pacote e, em seguida, novamente, __main__para que ele execute seu maincódigo. O Python 3.6 e posterior alertam sobre isso:

$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'

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:

Essa próxima armadilha existe em todas as versões atuais do Python, incluindo 3.3, e pode ser resumida na seguinte diretriz geral: "Nunca adicione um diretório de pacote ou qualquer diretório dentro de um pacote diretamente ao caminho do Python".

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:

    import os, sys
    _i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    if _i not in sys.path:
        sys.path.insert(0, _i)
    else:
        _i = None

    from sub.fileA import f1, f2
    from sub.fileB import Class3

    if _i:
        sys.path.remove(_i)
    del _i

Ou seja, modificamos o sys.pathtempo suficiente para alcançar nossas importações e, em seguida, colocamos de volta do jeito que era (excluindo uma cópia de _ise e somente se adicionamos uma cópia de _i).

torek
fonte
7

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:

if __name__ == '__main__':
   # run test code here...

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!

# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
    from codex import Codex # these are in same folder as module under test!
    from dblogger import DbLogger
else:
    from .codex import Codex
    from .dblogger import DbLogger

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.

Steve L
fonte
1
Isso realmente resolve. Mas é realmente desagradável. Por que esse não é o comportamento padrão ?!
lo tolmencre 04/04
4

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:

import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()
Federico
fonte
2

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 impmódulo que foi descontinuado desde a versão 3.4 para ser descartado a favor importlib. (Isso também é possível importlib? Não sei.) Ainda assim, o hack funciona por enquanto.

Exemplo para acessar membros de moduleXin a subpackage1partir de um script que reside na subpackage2pasta:

#!/usr/bin/env python3

import inspect
import imp
import os

def get_script_dir(follow_symlinks=True):
    """
    Return directory of code defining this very function.
    Should work from a module as well as from a script.
    """
    script_path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        script_path = os.path.realpath(script_path)
    return os.path.dirname(script_path)

# loading the module (hack, relying on deprecated imp-module)
PARENT_PATH = os.path.dirname(get_script_dir())
(x_file, x_path, x_desc) = imp.find_module('moduleX', [PARENT_PATH+'/'+'subpackage1'])
module_x = imp.load_module('subpackage1.moduleX', x_file, x_path, x_desc)

# importing a function and a value
function = module_x.my_function
VALUE = module_x.MY_CONST

Uma abordagem mais limpa parece ser modificar o sys.path usado para carregar os módulos, conforme mencionado por Federico.

#!/usr/bin/env python3

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    # __file__ should be defined in this case
    PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
   sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *
Lars
fonte
Parece melhor ... pena que ainda exija a incorporação do nome do diretório pai no arquivo ... talvez isso possa ser melhorado com o importlib. Talvez o importlib possa até ser monkeypatched para fazer com que a importação relativa "funcione" apenas em casos de uso simples. Eu vou dar um tempo nisso.
Andrew Wagner
Estou usando o python 2.7.14 embora. Algo assim ainda funcionaria?
user3474042
Acabei de testar as duas abordagens no python 2.7.10 e elas funcionaram bem para mim. Na verdade, você não tem o problema de um módulo imp obsoleto no 2.7, portanto, tanto melhor.
Lars
2

__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 usando python.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?

theodox
fonte
Ah, então você menciona -m. Isso faz com que seu módulo seja executado como um script - se você colocar um __name__ == '__main__', deverá ver que ele é '__main__' por causa do -m. Tente apenas importar seu módulo para outro módulo, para que ele não seja o nível superior ... que deve permitir a importação relativa
theodox
Tentei fazer essas importações do console, com o arquivo ativo sendo o módulo correto.
@Stopforgettingmyaccounts ...: O que você quer dizer com "arquivo ativo"?
BrenBarn
Eu uso o Pyscripter. Eu estava no moduleX.py quando executei essas importações: de .moduleY importa spam e de. Importar ModuleY.
Não importa .moduleY seguido por moduleY.spam ()?
theodox
2

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

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

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

Brad Dre
fonte
Esperando que você possa me guiar nisso. No link a seguir, se você for para o Caso 3, ele diz que a solução 1 não é possível. Por favor, você pode verificar isso e me avise. Isso vai me ajudar imensamente. chrisyeh96.github.io/2017/08/08/…
variável
@ variável Há um erro de digitação no link e não tenho permissão para editar. Observou o caso 3 e não seguiu exatamente o que você estava procurando. Quando tentei esse exemplo no python 2, não havia problemas que me faz pensar que perdi alguma coisa. Talvez você deva postar uma nova pergunta, mas precisa fornecer um exemplo mais claro. Caso 4 toques sobre o que eu estou falando na minha resposta aqui: você não pode ir até um diretório para importação relativa a menos que o intérprete começa em um diretório pai
Brad Dre
Obrigado, estou me referindo ao python 3 e aqui a pergunta stackoverflow.com/questions/58577767/…
variável
1

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.

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/

ec2604
fonte
-2

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

Sakshi Jain
fonte