Importar de um caminho relativo em Python


Respostas:


140

EDITAR novembro de 2014 (3 anos depois):

Python 2.6 e 3.x oferece suporte a importações relativas adequadas, onde você pode evitar fazer qualquer coisa hackeada. Com este método, você sabe que está obtendo uma importação relativa em vez de uma importação absoluta . O '..' significa ir para o diretório acima de mim:

from ..Common import Common

Como uma advertência, isso só funcionará se você executar seu python como um módulo, de fora do pacote. Por exemplo:

python -m Proj

Maneira hacky original

Este método ainda é comumente usado em algumas situações, onde você nem mesmo "instala" seu pacote. Por exemplo, é popular entre os usuários do Django.

Você pode adicionar Common / ao seu sys.path (a lista de caminhos que o Python procura para importar coisas):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) apenas fornece o diretório em que seu arquivo Python atual está, e então navegamos para 'Comum /' o diretório e importamos 'Comum' o módulo.


2
Não modifique o caminho dos módulos Python manualmente, pode ser apenas para hacks rápidos. Aprender o gerenciamento de pacotes Python usando distutils, ferramentas de configuração, etc. é geralmente uma habilidade necessária para resolver problemas como esse.
— Sascha Gottfried

1
@SaschaGottfried concorda totalmente, embora se você não estiver fazendo um pacote distribuível, provavelmente não fará diferença. Por exemplo, no Django você nunca realmente instala seu aplicativo com distutils, então o método acima é um hack fácil. Mas de qualquer forma eu editei a resposta com o que faria hoje em dia.
— Dave

32
Obrigado por responder a pergunta real em vez de pregar sobre a técnica adequada. Existem muitas boas razões para fazer importações relativas.
— musaranho

como você subiria mais de um nível?
— jxramos

10
para subir mais um nível, use um ponto adicional para cada nível. @jxramos ex: from ...myfilevai para../../myfile
— WattsInABox

10

Engraçado, o mesmo problema que acabei de conhecer, e eu consigo este trabalho da seguinte maneira:

combinando com o comando linux ln, podemos tornar as coisas muito mais simples:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

E, agora, se você deseja importar some_stuffdo arquivo: Proj/Common/Common.pypara o seu arquivo Proj/Client/Client.py:, assim:

# in Proj/Client/Client.py
from Common.Common import some_stuff

E, o mesmo se aplica a Proj/Server, Também funciona para o setup.pyprocesso, uma mesma questão discutida aqui , espero que ajude!


10

Não faça importação relativa.

Do PEP8 :

Importações relativas para importações intra-embalagem são altamente desencorajadas.

Coloque todo o seu código em um super pacote (ou seja, "myapp") e use subpacotes para cliente, servidor e código comum.

Atualização: " Python 2.6 e 3.x suporta importações relativas adequadas (...) ". Veja as respostas de Dave para mais detalhes.


1
Imagine que você adiciona algum código ao final do cliente e do servidor após a if __name__ == "__main__":linha ' '. Ou seja, você deseja poder usá-los como scripts independentes. Como fazer isso corretamente? Acho que é um caso de uso perfeitamente comum que deve ser suportado. Por que isso está desanimado?
— Jabba

83
Estou surpreso que "não faça isso" é a resposta aceita para um "como é que eu ..." questão (bem, exceto para Rails <g>.) Não são razões ocasionais de fazer isso. Eu uso uma solução semelhante à que Dave sugere.
— Tom Wilson

1
@TomWilson: Não é uma resposta pura do tipo "não faça isso". Há "faça assim" abaixo.
— Michał Šrajer

2
Alguém deveria contar para os caras da Numpy! Eles usam uma tonelada de importações relativas!
— Austin A

12
Esta resposta não se aplica às versões atuais do Python. A parte citada não é mais encontrada no PEP 8. Hoje em dia, diz-se: "importações relativas explícitas são uma alternativa aceitável para importações absolutas, especialmente quando se trata de layouts de pacotes complexos onde usar importações absolutas seria desnecessariamente prolixo"
— moooeeeep

8

Fazer uma importação relativa é absolutamente OK! Aqui está o que o meu pequeno faz:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py

1
Mas é melhor você saber para onde sys.argv [0] está realmente apontando - (provavelmente) não é o diretório em que você estava quando iniciou o python.
— CarlH

Este é um hack rápido, com muitas armadilhas. Mas a pergunta não era ainda melhor.
— Sascha Gottfried

1
Isso está escrito claramente, mas o hack original na resposta de Dave é melhor porque usa __file__para obter a relação adequada do arquivo atual
— John Neuhaus

4

O método de importação padrão já é "relativo", a partir do PYTHONPATH. O PYTHONPATH é por padrão, para algumas bibliotecas do sistema junto com a pasta do arquivo de origem original. Se você executar com -m para executar um módulo, o diretório atual será adicionado ao PYTHONPATH. Portanto, se o ponto de entrada do seu programa estiver dentro do Proj, useimport Common.Common deve funcionar dentro de Server.py e Client.py.

Não faça uma importação relativa. Não funcionará como você deseja.


1
Se isso for verdade, por que as principais respostas não dizem isso? Isso vai funcionar ou não?
— Anônimo
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.