Pergunta

Imagine esta estrutura de diretórios:

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

estou codificando mod1, e preciso importar algo de mod2.Como devo fazer isso?

tentei from ..sub2 import mod2 mas estou recebendo uma "Tentativa de importação relativa sem pacote".

Pesquisei no Google, mas encontrei apenas "sys.path manipulação" hacks.Não existe uma maneira limpa?


Editar:todo meu __init__.pyestão atualmente vazios

Editar2:Estou tentando fazer isso porque sub2 contém classes que são compartilhadas entre subpacotes (sub1, subX, etc.).

Editar3:O comportamento que procuro é o mesmo descrito em PEP 366 (obrigado João B)

Foi útil?

Solução

Todo mundo parece querer lhe dizer o que você deveria fazer, em vez de apenas responder à pergunta.

O problema é que você está executando o módulo como '__main__' passando mod1.py como argumento para o intérprete.

De PEP 328:

As importações relativas usam o atributo __name__ de um módulo para determinar a posição desse módulo na hierarquia do pacote.Se o nome do módulo não contiver nenhuma informação do pacote (por exemploestiver 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.

No Python 2.6, eles estão adicionando a capacidade de referenciar módulos relativos ao módulo principal. PEP 366 descreve a mudança.

Atualizar:Segundo Nick Coghlan, a alternativa recomendada é executar o módulo dentro do pacote usando a opção -m.

Outras dicas

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. Você corre python main.py.
  2. main.py faz: import app.package_a.module_a
  3. module_a.py faz import app.package_b.module_b

Alternativamente, 2 ou 3 poderiam usar: from app.package_a import module_a

Isso funcionará enquanto você tiver app em seu PYTHONPATH. main.py poderia estar em qualquer lugar então.

Então você escreve um setup.py copiar (instalar) todo o pacote e subpacotes do aplicativo para as pastas python do sistema de destino e main.py para direcionar as pastas de script do sistema.

Aqui está a solução que funciona para mim:

Eu faço as importações relativas como from ..sub2 import mod2e então, se eu quiser correr mod1.py então eu vou para o diretório pai de app e execute o módulo usando a opção python -m como python -m app.sub1.mod1.

A verdadeira razão pela qual este problema ocorre com as importações relativas é que as importações relativas funcionam tomando o __name__ propriedade do módulo.Se o módulo estiver sendo executado diretamente, então __name__ está configurado para __main__ e não contém nenhuma informação sobre a estrutura do pacote.E é por isso que python reclama do relative import in non-package erro.

Portanto, usando a opção -m você fornece as informações da estrutura do pacote ao python, por meio das quais ele pode resolver as importações relativas com êxito.

Encontrei esse problema muitas vezes ao fazer importações relativas.E, depois de ler todas as respostas anteriores, ainda não consegui descobrir como resolver isso, de forma limpa, sem precisar colocar código clichê em todos os arquivos.(Embora alguns dos comentários tenham sido realmente úteis, obrigado a @ncoghlan e @XiongChiamiov)

Espero que isso ajude alguém que está lutando contra o problema das importações relativas, porque passar pelo PEP não é realmente divertido.

"Guido vê a execução de scripts dentro de um pacote como um antipadrão" (rejeitadoPEP-3122)

Passei muito tempo tentando encontrar uma solução, lendo posts relacionados aqui no Stack Overflow e dizendo para mim mesmo "deve haver uma maneira melhor!".Parece que não existe.

Isso está resolvido 100%:

  • aplicativo/
    • principal.py
  • configurações/
    • local_setings.py

Importe settings/local_setting.py em app/main.py:

principal.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')
def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

Estou usando este trecho para importar módulos de caminhos, espero que ajude

explicação de nosklo's responda com exemplos

observação:todos __init__.py os arquivos estão vazios.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

app/pacote_a/fun_a.py

def print_a():
    print 'This is a function in dir package_a'

app/pacote_b/fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

principal.py

from app.package_b import fun_b
fun_b.print_b()

se você correr $ python main.py ele retorna:

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py faz: from app.package_b import fun_b
  • fun_b.py faz from app.package_a.fun_a import print_a

então arquivo na pasta package_b arquivo usado na pasta package_a, que é o que você deseja.Certo??

Infelizmente, este é um hack do sys.path, mas funciona muito bem.

Encontrei esse problema com outra camada:Eu já tinha um módulo com o nome especificado, mas era o módulo errado.

o que eu queria fazer era o seguinte (o módulo em que estava trabalhando era o módulo3):

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

Observe que já instalei o mymodule, mas na minha instalação não tenho "mymodule1"

e eu receberia um ImportError porque ele estava tentando importar dos meus módulos instalados.

Tentei fazer um sys.path.append e não funcionou.O que funcionou foi um sys.path.insert

if __name__ == '__main__':
    sys.path.insert(0, '../..')

É meio que um hack, mas fiz tudo funcionar!Então tenha em mente que se você quiser que sua decisão substituir outros caminhos então você precisa usar sys.path.insert(0, pathname) para fazê-lo funcionar!Este foi um ponto de discórdia muito frustrante para mim, muitas pessoas dizem para usar a função "anexar" ao sys.path, mas isso não funciona se você já tiver um módulo definido (acho um comportamento muito estranho)

Deixe-me colocar isso aqui para minha própria referência.Eu sei que não é um bom código Python, mas eu precisava de um script para um projeto em que estava trabalhando e queria colocar o script em um scripts diretório.

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

Como @EvgeniSergeev diz nos comentários ao OP, você pode importar código de um .py arquivo em um local arbitrário com:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Isto é tirado de esta resposta SO.

Dê uma olhada http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports.Você poderia fazer

from .mod1 import stuff

De Documento Python,

No Python 2.5, você pode mudar o comportamento de import para importações absolutas usando um from __future__ import absolute_import diretiva.Este comportamento de importação absoluta se tornará o padrão em uma versão futura (provavelmente Python 2.7).Uma vez que as importações absolutas são o padrão, import string sempre encontrará a versão da biblioteca padrão.É sugerido que os usuários comecem a usar importações absolutas tanto quanto possível, por isso é preferível começar a escrever from pkg import string no seu código

Achei mais fácil definir a variável de ambiente "PYTHONPATH" na pasta superior:

bash$ export PYTHONPATH=/PATH/TO/APP

então:

import sub1.func1
#...more import

claro, PYTHONPATH é "global", mas ainda não me causou problemas.

Além do que John B disse, parece que definir o __package__ variável deve ajudar, em vez de mudar __main__ o que poderia estragar outras coisas.Mas até onde pude testar, não funciona completamente como deveria.

Estou com o mesmo problema e nem o PEP 328 nem o 366 resolvem o problema completamente, pois ambos, no final das contas, precisam que o chefe do pacote seja incluído no sys.path, até onde eu pude entender.

Devo mencionar também que não descobri como formatar a string que deveria entrar nessas variáveis.É isso "package_head.subfolder.module_name" ou o que?

Suponha que você execute no nível superior, depois em mod1 usar:

import sub2.mod2 

em vez de

from ..sub2 import mod2
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top