Cada ferramenta abordada nesta seção - venv, uv, Poetry, PDM - está resolvendo um problema subjacente: decidir quais arquivos no disco uma determinada instrução import realmente carrega, e fazer isso de forma consistente entre máquinas.
Fundamentos de Ambientes e Empacotamento aborda os comandos práticos para criar um ambiente e instalar um pacote.
Esta página permanece um nível acima: os mecanismos de caminho de busca que tornam o isolamento possível em primeiro lugar, e o modelo de resolução que transforma um pyproject.toml em um conjunto concreto e reproduzível de pacotes instalados.
Um import é resolvido percorrendo uma lista ordenada de diretórios (sys.path); um ambiente virtual funciona alterando o que essa lista contém, não fazendo sandbox do interpretador em si.
Por Que Importa: A maioria dos bugs de "versão errada do pacote foi importada" e "funciona na minha máquina" remonta a uma lacuna entre o caminho de busca do interpretador e o que um desenvolvedor assume que está instalado - entender a ordem de busca fecha essa lacuna.
Conceitos Chave:sys.path, site-packages, o sistema de importação, resolução de dependências, o lockfile, metadados PEP 621.
Quando Usar Este Modelo: Depurando por que a versão errada de um pacote foi importada, escolhendo entre uv, Poetry e PDM para uma equipe, raciocinando sobre instalações editáveis e entendendo por que o CI precisa de um lockfile mesmo quando pyproject.toml não mudou.
Limitações / Trade-offs: Intervalos de versão expressam intenção, não garantia - uma dependência ainda pode publicar um lançamento tecnicamente compatível que quebre seu código, e nenhum lockfile protege contra um pacote que foi comprometido desde o momento em que foi publicado.
Tópicos Relacionados: o sistema de importação de módulos, empacotamento e publicação, índices de pacotes privados, reprodutibilidade de CI.
Um interpretador Python não sabe, ao iniciar, onde as dependências do seu projeto residem.
Toda vez que o código executa import httpx, o interpretador percorre uma lista ordenada de diretórios chamada sys.path, verificando cada um em ordem em busca de um módulo ou pacote correspondente, e para na primeira correspondência que encontra.
Essa lista é construída a partir de algumas fontes: o diretório que contém o script sendo executado, a variável de ambiente PYTHONPATH se definida, e um conjunto de locais de bibliotecas padrão e de terceiros - o mais importante, para este tópico, é site-packages, o diretório onde pip e seus pares realmente copiam os pacotes instalados.
Um ambiente virtual é melhor entendido como um pequeno truque aplicado a essa ordem de busca do que como uma sandbox em torno do próprio binário do interpretador.
Executar python -m venv .venv cria um novo diretório com sua própria pasta site-packages e uma cópia (ou symlink) do interpretador; ativá-lo ajusta sys.path e o PATH do shell para que python e pip dentro desse shell apontem primeiro para o site-packages local do projeto.
Dois projetos podem, portanto, cada um depender de uma versão diferente do mesmo pacote sem conflito algum, porque cada um tem seu próprio diretório site-packages e o interpretador nunca precisa reconciliar os dois.
Uma analogia útil: sys.path é a ordem de busca de um bibliotecário em vários ramos do mesmo sistema de biblioteca.
Peça um livro e o bibliotecário verifica o ramo mais próximo primeiro (o site-packages do próprio projeto), depois ramos mais amplos (a biblioteca padrão, quaisquer instalações globais), retornando qualquer cópia que seja encontrada primeiro - não necessariamente a que você esperava se dois ramos por acaso contiverem edições diferentes.
Instalar um pacote com pip, uv ou qualquer outro instalador é, por baixo da cerimônia da linha de comando, um ato de duas etapas: buscar metadados e um artefato de distribuição (uma wheel, geralmente) de um índice de pacotes como PyPI, então descompactar os arquivos dessa wheel no site-packages do ambiente ativo.
Nada mais misterioso acontece - não há um registro separado de "o que está instalado" além dos arquivos que fisicamente existem naquele diretório, que é exatamente por que deletar um .venv e recriá-lo é uma maneira completamente segura de começar de novo.
Resolução de dependências é o problema mais difícil que fica em cima desse mecanismo: um projeto raramente declara apenas pacotes sem sub-dependências, então a ferramenta deve ler cada intervalo de versão declarado - tanto as dependências diretas do projeto quanto as dependências transitivas de cada dependência - e encontrar um conjunto consistente de versões que satisfaça todas elas simultaneamente.
pyproject.toml expressa essa intenção como intervalos (httpx>=0.28,<1), enquanto um lockfile (uv.lock, poetry.lock) registra as versões exatas que o resolvedor realmente escolheu na última vez que executou, incluindo pacotes transitivos que o desenvolvedor nunca nomeou explicitamente.
Essa separação - intervalos expressam o que é aceitável, o lockfile registra o que foi realmente escolhido - é o modelo mental mais importante em toda esta seção, porque explica por que uv sync --frozen no CI se comporta de maneira completamente diferente de um uv sync simples: o primeiro se recusa a tocar no lockfile e instala exatamente o que ele diz, o segundo está disposto a re-resolver se pyproject.toml mudou.
Uma instalação editável (pip install -e . ou uv pip install -e .) modifica essa imagem de uma maneira específica: em vez de copiar os arquivos do pacote para site-packages, ele solta um pequeno ponteiro (historicamente um arquivo .pth, agora mais frequentemente um hook finder leve) que diz ao sistema de importação para procurar diretamente no diretório de origem.
É por isso que editar um arquivo em src/myapp/ tem efeito na próxima import sem reinstalar - o local "instalado" resolvido e a cópia de trabalho do desenvolvedor são, deliberadamente, os mesmos arquivos.
Três ferramentas dominam este espaço hoje - uv, Poetry e PDM - e vale a pena ser preciso sobre o que realmente difere entre elas, porque não é o problema de resolução em si.
Todas as três leem metadados de pyproject.toml (amplamente padronizados pelo PEP 621), constroem um grafo de dependências e escrevem um lockfile; onde elas divergem é a velocidade de implementação do resolvedor, o formato do lockfile e o fluxo de trabalho circundante (grupos de dependência, suporte a monorepo/workspace, comandos de publicação).
uv, escrito em Rust, resolve e instala uma ordem de magnitude mais rápido do que ferramentas baseadas em pip na maioria dos projetos, que é a principal razão pela qual se tornou a recomendação padrão para novos projetos Python 3.14.
Índices de pacotes privados complicam o modelo de resolução de uma forma que vale a pena nomear explicitamente: quando um resolvedor é apontado para um índice interno (via UV_INDEX_URL ou [[tool.uv.index]]), ele ainda executa o mesmo algoritmo de resolução de grafo, apenas contra metadados diferentes - o risco é que um índice mal configurado possa servir silenciosamente um pacote diferente (ou malicioso) sob um nome que sombreia um público, que é por que credenciais e configuração de índice merecem o mesmo escrutínio que as próprias dependências.
Reproduzir um ambiente "do zero" - o teste que toda configuração de empacotamento deve passar - é realmente uma afirmação sobre a completude do lockfile: se uv sync --frozen (ou o equivalente Poetry/PDM) em um checkout limpo produz uma instalação funcional sem tocar na rede para nada além de buscar artefatos fixados, o lockfile está fazendo seu trabalho.
Ferramenta
Força
Fraqueza
Melhor Encaixe
venv + pip
Instalação extra zero, vem com Python
Sem lockfile embutido ou resolvedor rápido
Scripts pequenos, ensino, dependências mínimas
uv
Resolução/instalação muito rápida, binário único, substituto direto do pip
Ferramenta mais nova, ecossistema de plugins menor que o pip
Escolha padrão para novos projetos Python 3.14
Poetry
Fluxo de trabalho maduro, grupos de dependência, ferramentas de publicação
Historicamente resolvedor mais lento que uv
Equipes já investidas nas convenções de projeto do Poetry
PDM
PEP 582/621-forward, backends flexíveis
Comunidade menor que Poetry
Equipes que desejam ferramentas "padrão primeiro" sem lock-in do fornecedor
"Um ambiente virtual isola o próprio interpretador." Ele isola site-packages e ajusta sys.path - o mesmo binário do interpretador (ou uma cópia dele) ainda é executado; nada sobre o tempo de execução da linguagem muda entre os ambientes.
"pyproject.toml me diz exatamente o que está instalado." Ele apenas declara intervalos aceitáveis - o lockfile registra o que foi realmente resolvido, e é nisso que uma instalação reproduzível confia.
"Um intervalo de caractere de acento circunflexo ou de lançamento compatível nunca pode quebrar meu código." Pode, sempre que o lançamento de um editor não seguir corretamente a versionamento semântico; o intervalo expressa uma expectativa, não um contrato imposto.
"Instalações editáveis são apenas uma conveniência sem diferença real de uma instalação normal." Elas mudam onde o sistema de importação procura o pacote inteiramente, apontando para a árvore de origem de trabalho em vez de um artefato copiado, que é exatamente por que elas importam para o desenvolvimento local e monorepos.
"Ferramentas mais rápidas como uv significam um algoritmo de resolução fundamentalmente diferente." O problema de resolução - encontrar um conjunto de versões consistente em um grafo de dependências - é o mesmo; a vantagem do uv é um resolvedor e instalador muito mais rápido baseado em Rust, não um modelo diferente.
O que realmente acontece quando executo `import nome_do_pacote`?
O interpretador percorre sys.path em ordem, verificando cada diretório em busca de um módulo ou pacote correspondente, e para na primeira correspondência - geralmente o site-packages do ambiente ativo.
Qual é a diferença prática entre um ambiente virtual e instalar pacotes globalmente?
Um ambiente virtual dá a um projeto seu próprio diretório site-packages inserido em sys.path, então suas dependências nunca entram em conflito com as de outro projeto - uma instalação global compartilha um único site-packages em todos os scripts da máquina.
Por que `pip install algum-pacote` às vezes instala uma versão diferente da que eu espero?
O resolvedor está satisfazendo um intervalo, não uma versão específica - se o intervalo permite um lançamento mais recente e um foi publicado desde sua última instalação, a resolução pode legitimamente escolhê-lo, a menos que um lockfile fixe a versão exata.
Qual o propósito de um lockfile se `pyproject.toml` já lista minhas dependências?
pyproject.toml declara o que é aceitável; o lockfile declara o que foi realmente escolhido, incluindo todas as dependências transitivas que você nunca nomeou diretamente - essa é a única maneira de garantir que duas máquinas instalem código idêntico.
Por que `uv sync --frozen` falha às vezes quando `uv sync` sozinho teria sucesso?
--frozen se recusa a re-resolver ou tocar no lockfile, então se pyproject.toml mudou desde que o lockfile foi gerado pela última vez, ele falha ruidosamente em vez de se desviar silenciosamente - essa rigidez é exatamente o que o torna seguro para CI.
Uma instalação editável copia meu código para `site-packages`?
Não - ela instala um pequeno ponteiro que redireciona o sistema de importação para o seu diretório de origem de trabalho, para que as edições entrem em vigor imediatamente sem reinstalar.
Por que `uv` é mais rápido que pip para o mesmo problema de resolução?
É uma implementação do zero em Rust com um resolvedor e instalador muito mais rápidos, não um algoritmo de resolução diferente - o problema de satisfação de grafo subjacente que ele resolve é o mesmo que pip e Poetry resolvem.
Dois projetos Python diferentes na mesma máquina podem depender de versões incompatíveis do mesmo pacote?
Sim, sem nenhum conflito - porque o ambiente virtual de cada projeto tem seu próprio site-packages, o interpretador nunca precisa reconciliar as duas instalações entre si.
Um índice de pacotes privado muda como a resolução funciona?
Não, o resolvedor ainda constrói e satisfaz o mesmo grafo de dependências - ele apenas lê metadados de pacotes de um índice diferente (ou adicional), que é por que índices privados mal configurados são uma preocupação real de segurança, não apenas um inconveniente de rede.
O `PYTHONPATH` ainda é relevante com ferramentas modernas como `uv`?
Raramente é definido manualmente em projetos que usam uv, Poetry ou PDM, já que o mecanismo de ambiente virtual já ajusta sys.path corretamente - PYTHONPATH é mais relevante agora para casos especializados como scripts ad-hoc fora da estrutura do projeto.
Por que as equipes padronizam um formato de lockfile em vez de misturar ferramentas?
O formato de lockfile e o comportamento do resolvedor de cada ferramenta diferem ligeiramente, e confirmar mais de um (digamos, tanto uv.lock quanto poetry.lock) convida à deriva entre eles - apenas o resultado da resolução de uma ferramenta deve ser tratado como a fonte da verdade por projeto.
O fixar de versão no lockfile protege contra uma atualização maliciosa de pacote?
Ele protege contra um pacote ser silenciosamente trocado ou alterado posteriormente, já que o lockfile pode registrar hashes de integridade - ele não faz nada sobre um pacote que já era malicioso ou comprometido na versão que você fixou.