Modularidade e empacotamento são recursos presentes em toda linguagem de programação relevante, pois permitem que nós, desenvolvedores, reutilizemos facilmente trechos de código recorrentes (também conhecidos como módulos).

Em Python, podemos adicionar pacotes como dependências do nosso projeto instalando-os com algum gerenciador de pacotes, como o pip:

pip install requests==2.30.0
pip install pytest pytest-cov

No exemplo acima, estamos instalando a biblioteca requests na versão 2.30.0 na primeira linha e, na segunda, as bibliotecas pytest e pytest-cov. Como não estamos especificando uma versão para pytest e pytest-cov, as versões mais recentes serão instaladas.

Isso é ótimo, mas surge um problema quando trabalhamos em vários projetos simultaneamente, compartilhamos projetos com outras pessoas ou até mesmo usamos a máquina para estudar. O gerenciamento de pacotes específicos por projeto torna-se desafiador.

Desvantagens de instalações globais (sem ambientes virtuais)

Antes de falarmos sobre ambientes virtuais, vamos imaginar uma situação. Suponha que você começou um novo projeto e precise instalar pandas, requests e jinja para ele. Você simplesmente executa:

pip install Jinja2 requests pandas

Depois disso, você compartilha o projeto com outra pessoa, usando git para versioná-lo e enviá-lo para um repositório remoto como o GitHub. Agora, outras pessoas precisam contribuir com o projeto, mas ao tentar executá-lo, veem uma mensagem de erro dizendo “no module named ‘pandas’”. Isso faz sentido, já que você está compartilhando apenas o código-fonte no repositório e não todo o seu ambiente (seu interpretador python, pacotes instalados, etc.).

Captura de tela mostrando o erro "no module named 'pandas'"

Para resolver o problema, você poderia simplesmente instruir as pessoas do projeto a executarem pip install Jinja2 requests pandas. Mas isso não resolve completamente. Algumas pessoas podem já ter versões diferentes do requests instaladas em suas máquinas, o que pode não gerar o mesmo erro, mas sim erros diferentes devido a incompatibilidades entre versões.

Congelando dependências

Você precisa de uma forma de compartilhar exatamente as mesmas versões das dependências que está usando no projeto. Felizmente, o Python traz uma solução para isso: o subcomando freeze do pip. Com ele, você pode listar todas as dependências instaladas (inclusive as dependências das suas dependências) com as versões correspondentes e salvar em um arquivo de texto, que depois pode ser usado para instalar tudo corretamente:

pip freeze > requirements.txt

O comando acima é um padrão comum no Python para criar um arquivo requirements.txt com as dependências atualmente instaladas (ele “congela” suas versões). Depois, ao configurar o projeto em uma nova máquina, basta executar:

pip install -r requirements.txt

Esse comando instalará tudo o que está listado no seu requirements.txt.

Nota: mantenha este arquivo na raiz do seu projeto para facilitar o fluxo de trabalho.

Agora temos um comando simples para instalar todas as dependências, e só precisamos garantir que o requirements.txt esteja atualizado executando pip freeze > requirements.txt sempre que incluirmos uma nova dependência no projeto, certo? Não exatamente. Ainda há um problema.

Pacotes instalados globalmente

Lembra quando instalamos requests 2.30, pytest e pytest-cov no início deste artigo? Essas bibliotecas não fazem parte do projeto que criamos depois, mas mesmo assim você notará que seu requirements.txt as inclui (junto com toda a árvore de dependências). Veja só:

Conteúdo do arquivo requirements destacando dependências de requests e pytest

Isso pode ser um problema, pois instalará pacotes desnecessários e pode até afetar a resolução de dependências do pip install. Além disso, imagine a bagunça ao precisar trabalhar com versões diferentes do mesmo pacote em projetos distintos na mesma máquina…

Para resolver isso, podemos usar os ambientes virtuais do Python.

venv do Python

O ambiente virtual em Python — ou venv — é um recurso para isolar o contexto do seu projeto (interpretador, bibliotecas instaladas etc.) da configuração global do Python. Na prática, os pacotes instalados dentro de um ambiente virtual não entram em conflito com os pacotes globais da máquina. É uma boa prática criar um venv para cada projeto. A seguir, veremos um passo a passo de como usar e entender o venv.

Criar um venv

O Python vem com um módulo interno chamado venv para criar ambientes virtuais. Você pode criar um novo ambiente assim:

python -m venv venv 
# nota: no seu sistema, o comando pode ser python3 ou py em vez de python...

No comando acima, python -m venv cria o ambiente virtual e o último venv é apenas o nome da pasta que será criada (pode ser outro nome, mas “venv” é o mais comum). Essa pasta conterá o interpretador Python, bibliotecas instaladas etc.

Nota: Não se preocupe com a pasta venv gerada — o Python gerencia tudo internamente, você não precisa mexer nela.

Seu venv está criado, mas ainda não está ativo, então você continua no ambiente normal.

Ativar o venv

Agora que temos um venv para o projeto, podemos ativá-lo:

# Linux e MacOS:
source venv/bin/activate

# Windows:
.\venv\Scripts\activate

Você notará que “venv” (ou o nome que escolheu) aparece em verde no terminal, indicando que o ambiente foi ativado com sucesso.

Seu shell permanece praticamente o mesmo — apenas o interpretador Python é trocado pelo do venv.

Trabalhando dentro do venv

A primeira coisa a notar é que você não tem acesso aos pacotes instalados globalmente. Por exemplo, tentar importar pandas gerará ModuleNotFoundError, o que faz sentido, pois o ambiente é novo e está isolado da sua instalação global.

Vamos reinstalar as dependências necessárias e congelá-las:

pip install Jinja2 requests pandas 
pip freeze > requirements.txt

Você pode usar os comandos python e pip normalmente. A diferença é que aqui eles apontam para o ambiente virtual, não para a instalação global.

Veja a diferença entre o requirements.txt anterior (à esquerda) e o novo, gerado dentro do venv (à direita):

Comparação entre o requirements antes e depois do venv

De 22 dependências, passamos para 13 — uma redução de 9 dependências, ou cerca de 40% a menos!

Nota: Quando você fecha o terminal ou o IDE, o venv é desativado. Então, sempre que abrir novamente, será necessário reativá-lo.

Desativar o venv

Quando quiser voltar ao ambiente global, basta rodar:

deactivate

Considerações finais

Perfeito — agora podemos trabalhar com ambientes virtuais e ter um contexto isolado por projeto. Mas ainda há algumas observações importantes.

Git

A pasta do ambiente virtual contém muitos arquivos e costuma ser grande. Além disso, o gerenciador de pacotes pode se comportar de forma diferente em cada máquina, então é importante adicionar a pasta venv ao .gitignore. Assim, você mantém apenas o código-fonte no repositório, e qualquer pessoa pode reproduzir o ambiente instalando as dependências.

Pipelines de CI/CD

Em pipelines de CI/CD normalmente já existe um ambiente isolado, então não há necessidade de criar e ativar um venv antes de instalar as dependências. Você pode ir direto para o pip install -r requirements.txt e executar o código.

Usuários do VSCode

Existem várias extensões legais de Python no VSCode, mas a essencial, na minha opinião, é a Python da Microsoft.

Extensão Python no marketplace do VSCode

Essa extensão traz recursos como intellisense, debugging, entre outros. Para aproveitar tudo, certifique-se de que o interpretador Python selecionado no VSCode é o do seu venv.

Suponha que adicionamos uma nova dependência ao projeto (apenas no venv):

pip install matplotlib 
pip freeze > requirements.txt

Veja o que acontece se não estivermos usando o interpretador correto:

VSCode alertando que matplotlib não foi encontrado

Note que temos o matplotlib instalado no venv, mas o VSCode ainda mostra um aviso de que o pacote não foi encontrado. Se tentarmos executar o script pelo botão “run”:

VSCode exibindo erro ao executar o script

Agora, executando o mesmo script pelo terminal com o venv ativo:

Execução bem-sucedida no terminal com venv ativo

Isso mostra que o VSCode está usando o interpretador errado. Para corrigir, basta clicar no canto inferior direito (onde aparece o Python ativo, em vermelho na imagem) e selecionar o interpretador correto no menu que será exibido (você o identifica pelo caminho do venv, também destacado em vermelho).

Selecionando o interpretador correto no VSCode

Após isso, os avisos somem, o intellisense volta a funcionar e o botão de execução roda sem erros:

VSCode funcionando corretamente após selecionar o interpretador

No canto inferior direito, você verá o interpretador do seu venv sendo exibido.


Em conclusão, os ambientes virtuais são uma ferramenta poderosa para gerenciar dependências e criar contextos isolados em Python. Eles garantem instalações consistentes e evitam conflitos entre projetos diferentes. Se quiser se aprofundar no tema, confira também: https://realpython.com/python-virtual-environments-a-primer/