PYTHONPATH vs. sys.path

92

Outro desenvolvedor e eu discordamos sobre se PYTHONPATH ou sys.path devem ser usados ​​para permitir que Python encontre um pacote Python em um diretório de usuário (por exemplo, desenvolvimento).

Temos um projeto Python com uma estrutura de diretório típica:

Project
    setup.py
    package
        __init__.py
        lib.py
        script.py

Em script.py, precisamos fazer import package.lib. Quando o pacote é instalado em sites-packages, script.py pode encontrar package.lib.

Ao trabalhar a partir de um diretório de usuário, entretanto, algo mais precisa ser feito. Minha solução é definir meu PYTHONPATH para incluir "~ / Projeto". Outro desenvolvedor deseja colocar esta linha de código no início de script.py:

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

Para que Python possa encontrar a cópia local de package.lib.

Acho que é uma má ideia, já que esta linha só é útil para desenvolvedores ou pessoas que executam uma cópia local, mas não posso dar uma boa razão para que seja uma má ideia.

Devemos usar PYTOHNPATH, sys.path ou tudo bem?

Gaefan
fonte
4
Parece que os votos e as respostas estão divididos de maneira bastante uniforme, com uma leve tendência ao uso de PYTHON_PATH, embora isso possa ser uma amostragem de ruído ou distorção não intencional da pergunta.
AJP

Respostas:

42

Se o único motivo para modificar o caminho for para desenvolvedores trabalhando em sua árvore de trabalho, você deve usar uma ferramenta de instalação para configurar seu ambiente para você. virtualenv é muito popular, e se você estiver usando ferramentas de instalação, você pode simplesmente executar setup.py developpara semi-instalar a árvore de trabalho em sua instalação atual do Python.

Ned Batchelder
fonte
10
Você pode oferecer um pouco mais de esclarecimento sobre isso? Mesmo se você criar um ambiente conda / virtualenv, como isso colocaria o diretório de nível superior em seu caminho python?
compguy24 de
38

Eu odeio PYTHONPATH. Acho frágil e irritante definir por usuário (especialmente para usuários de daemon) e acompanhar conforme as pastas do projeto se movem. Eu preferiria definirsys.path nos scripts invoke para projetos autônomos.

No entanto, sys.path.appendnão é a maneira de fazer isso. Você pode obter facilmente duplicatas e não classifica os .ptharquivos. Melhor (e mais legível): site.addsitedir.

E script.pynormalmente não seria o lugar mais apropriado para fazer isso, pois está dentro do pacote que você deseja disponibilizar no caminho. Módulos de biblioteca certamente não devem se tocar sys.path. Em vez disso, você normalmente teria um script hashbanged fora do pacote que você usa para instanciar e executar o aplicativo, e é nesse script de wrapper trivial que você colocaria detalhes de implantação como sys.path-frobbing.

bobince
fonte
16
O problema site.addsitediré que ele faz um appendon sys.path, o que significa que um pacote instalado terá precedência sobre o pacote local em desenvolvimento (e isso pode causar uma confusão). sys.path.insert(0...é necessário para superar isso.
Eli Bendersky
5
@EliBendersky: deveria ser sys.path.insert(1. stackoverflow.com/q/10095037/125507
endolith
12

Em geral, eu consideraria a configuração de uma variável de ambiente (como PYTHONPATH) uma prática ruim. Embora isso possa ser bom para uma depuração isolada, usar isso como
uma prática regular pode não ser uma boa ideia.

O uso da variável de ambiente leva a situações como "funciona para mim", quando outra
pessoa relata problemas na base de código. Além disso, pode-se realizar a mesma prática com o ambiente de teste, levando a situações como a execução de testes bem para um desenvolvedor em particular, mas provavelmente falhando quando alguém os inicia.

sateesh
fonte
5

Eu acho que, neste caso, usar PYTHONPATH é uma coisa melhor, principalmente porque ele não introduz código desnecessário (questionável).

Afinal, se você pensar bem, seu usuário não precisa disso sys.path, porque seu pacote será instalado em sites-packages, porque você estará usando um sistema de empacotamento.

Se o usuário escolher executar a partir de uma "cópia local", como você a chama, observei que a prática usual é afirmar que o pacote precisa ser adicionado a PYTHONPATH manualmente, se usado fora dos pacotes do site .

brilhante
fonte
5

Junto com os muitos outros motivos já mencionados, você também pode apontar que a codificação permanente

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

é frágil porque presume a localização de script.py - só funcionará se script.py estiver localizado em Projeto / pacote. Ele será interrompido se um usuário decidir mover / copiar / symlink script.py (quase) para qualquer outro lugar.

unutbu
fonte
2

Nem hackear PYTHONPATHnem sys.pathé uma boa ideia pelos motivos mencionados. E para vincular o projeto atual à pasta de pacotes do site, há realmente uma maneira melhor do que python setup.py develop, conforme explicado aqui :

pip install --editable path/to/project

Se você ainda não tem um setup.py na pasta raiz do seu projeto, este é bom o suficiente para começar:

from setuptools import setup
setup('project')
Peter
fonte