Por que usar sys.path.append (path) em vez de sys.path.insert (1, path)?

88

Edit: com base no comentário de Ulf Rompe, é importante que você use "1" em vez de "0" , caso contrário, você quebrará sys.path .

Eu tenho feito python por um bom tempo (mais de um ano), e sempre fico confuso sobre por que as pessoas recomendam que você use em sys.path.append()vez de sys.path.insert(). Deixe-me demonstrar.

Digamos que eu esteja trabalhando em um módulo chamado PyWorkbooks (que está instalado no meu computador), mas ao mesmo tempo estou trabalhando em um módulo diferente (digamos PyJob) que incorpora PyWorkbooks. Como estou trabalhando no PyJob, encontro erros nos PyWorkbooks que estou corrigindo, então gostaria de importar uma versão de desenvolvimento.

Existem várias maneiras de trabalhar em ambos (eu poderia colocar meu projeto PyWorkbooks dentro do PyJob, por exemplo), mas às vezes ainda terei de brincar com o caminho. No entanto, não posso simplesmente fazer um sys.path.append()para a pasta onde está o PyWorkbooks . Por quê? Porque o python vai encontrar meus PyWorkbooks instalados primeiro!

É por isso que você deve fazer um sys.path.insert (1, path_to_dev_pyworkbooks)

Em suma:

sys.path.append(path_to_dev_pyworkbooks)
import PyWorkbooks # does NOT import dev pyworkbooks, imports installed one

ou:

sys.path.insert(1, path_to_dev_pyworkbooks) # based on comments you should use **1 not 0**
import PyWorkbooks # imports correct file

Isso me causou alguns problemas no passado e eu realmente gostaria que nós (como uma comunidade) começássemos a recomendar sys.path.insert(1, path), como se você estivesse inserindo manualmente um caminho, acho que é seguro dizer que esse é o caminho que você deseja usar!

Ou eu tenho algo errado? É uma questão que às vezes me incomoda e eu queria que fosse abertamente!

Garrett Berg
fonte
3
Eu fiz, sys.path.insert(1, dev_folder)mas ainda não encontrei o módulo dev, e apenas usando o módulo instalado. Como faço para corrigir isso?
endolith

Respostas:

47

Se você tiver várias versões de um pacote / módulo, precisará usar o virtualenv (ênfase minha):

virtualenv é uma ferramenta para criar ambientes Python isolados.

O problema básico a ser tratado é o das dependências e versões e, indiretamente, das permissões. Imagine que você tenha um aplicativo que precisa da versão 1 do LibFoo, mas outro aplicativo requer a versão 2. Como você pode usar esses dois aplicativos? Se você instalar tudo /usr/lib/python2.7/site-packages(ou qualquer que seja o local padrão da sua plataforma), é fácil acabar em uma situação em que você atualiza acidentalmente um aplicativo que não deveria ser atualizado.

Ou, de forma mais geral, e se você quiser instalar um aplicativo e deixá-lo como está ? Se um aplicativo funcionar, qualquer alteração em suas bibliotecas ou nas versões dessas bibliotecas pode interromper o aplicativo.

Além disso, e se você não puder instalar pacotes no site-packagesdiretório global ? Por exemplo, em um host compartilhado.

Em todos esses casos, virtualenvpode te ajudar. Ele cria um ambiente que possui seus próprios diretórios de instalação, que não compartilha bibliotecas com outros ambientes virtualenv (e opcionalmente também não acessa as bibliotecas instaladas globalmente).

É por isso que as pessoas consideram insert(0, errado - é uma solução provisória incompleta para o problema de gerenciamento de vários ambientes.

agf
fonte
Obrigado, eu sabia vagamente que algo assim existia, mas eu realmente não verifiquei até agora. Então o que eu teria que fazer com isso seria rodar tudo, desde o interpretador no ambiente virtual ... isso poderia funcionar também. Obrigado!
Garrett Berg,
1
Esta é uma sugestão, mas não responde diretamente à pergunta (por exemplo, tenho fortes motivos para não usar virtualenve na verdade estou procurando a resposta associada ao OP)
javadba
@javadba Isso pode ser verdade para o seu caso, mas a maioria das pessoas que fazem essa pergunta deveriam usar venv.
agf
45

Se você realmente precisa usar sys.path.insert, considere deixar sys.path [0] como está:

sys.path.insert(1, path_to_dev_pyworkbooks)

Isso pode ser importante, pois o código de terceiros pode depender da conformidade da documentação sys.path :

Como inicializado na inicialização do programa, o primeiro item desta lista, caminho [0], é o diretório que contém o script que foi usado para invocar o interpretador Python.

Ulf Rompe
fonte
13

você está confundindo o conceito de anexar e anexar. o código a seguir é antecedente:

sys.path.insert(1,'/thePathToYourFolder/')

ele coloca a nova informação no início (bem, em segundo lugar, para ser mais preciso) da sequência de busca que seu intérprete irá percorrer. sys.path.append()coloca as coisas no final da sequência de pesquisa.

é aconselhável que você use algo parecido, em virtualenvvez de codificar manualmente os diretórios de seus pacotes no PYTHONPATHeverytime. para configurar vários ecossistemas que separam seus pacotes de site e possíveis versões de python, leia estes dois blogs:

  1. introdução aos ecossistemas python

  2. inicialização de ambientes virtuais python

se você decidir seguir o caminho do isolamento do ambiente, certamente se beneficiará ao consultar o virtualenvwrapper: http://www.doughellmann.com/docs/virtualenvwrapper/

samkhan13
fonte
1
Os links "introdução de ecossistemas python", "bootstrapping de ambientes virtuais python" foram suspensos, considere revitalizá-los.
Pradeep Singh