11  Módulos e Bibliotecas em Python

De uma receita solta para um livro de receitas organizado: organizando seu código!

11.1 O que você vai aprender neste capítulo?

  1. O que são módulos e por que todo programador precisa deles
  2. Como criar seus próprios módulos e organizar código em arquivos separados
  3. Diferentes formas de importar: import, from ... import, import ... as
  4. Bibliotecas que já vêm com Python: datetime, random, math, os, pathlib
  5. Como instalar bibliotecas externas com pip install
  6. Estruturar projetos maiores de forma organizada
  7. Convenções e boas práticas para módulos

🎓 Vindo do Capítulo 10? Ótimo! Agora que você já sabe lidar com erros, vamos organizar seu código de forma profissional.

🎯 Meta: Ao final deste capítulo, você vai conseguir criar módulos próprios, usar bibliotecas externas e organizar projetos Python como um desenvolvedor experiente.

⚠️ Por que isso importa: Sem módulos, você teria que repetir código infinitamente. Aqui você aprende a criar “receitas” reutilizáveis!

11.2 De uma Receita Solta para um Livro de Receitas

Lembra quando falamos sobre receitas de bolo? Até agora você tem uma receita aqui, outra ali… Mas e se você quisesse criar um livro completo de receitas?

Imagine que você tem:

  • Uma receita de bolo de chocolate
  • Uma receita de brigadeiro
  • Uma receita de coxinha
  • Uma receita de café

O problema: Cada receita está em um papel separado, espalhada pela casa. Quando você quer fazer um bolo, tem que procurar a receita. Quando quer fazer brigadeiro, tem que procurar outra receita.

A solução: Organizar tudo em um livro de receitas!

  • 📖 Índice no início (para encontrar rapidamente)
  • 📄 Cada receita em uma página separada
  • 🔗 Referências entre receitas (“veja também a receita de cobertura na página 15”)

💡 Em programação, isso se chama MÓDULOS! Cada arquivo .py é como uma página do seu livro de receitas, e o import é como consultar o índice para encontrar a receita que você quer!

11.3 O que são Módulos?

Módulo é simplesmente um arquivo Python (.py) que contém código que você pode usar em outros programas.

11.3.1 Analogia Perfeita

Pense em um livro de receitas:

Livro de Receitas Módulo Python
📖 Livro completo 📁 Projeto Python
📄 Página com receita de bolo 📄 arquivo bolo.py
📄 Página com receita de brigadeiro 📄 arquivo brigadeiro.py
📑 Índice no início 📑 import statements
🔍 “Veja página 15” 🔍 from bolo import fazer_cobertura

11.3.2 Por que usar módulos?

Sem módulos (o problema):

# arquivo_principal.py - TUDO em um arquivo só
def calcular_area_circulo(raio):
    return 3.14159 * raio ** 2

def calcular_area_retangulo(largura, altura):
    return largura * altura

def calcular_imc(peso, altura):
    return peso / (altura ** 2)

# ... mais 50 funções aqui ...
# Arquivo gigante, difícil de encontrar coisas!

Com módulos (a solução):

# arquivo_principal.py - Limpo e organizado
from geometria import calcular_area_circulo, calcular_area_retangulo
from saude import calcular_imc

# Usar as funções normalmente
area = calcular_area_circulo(5)
imc = calcular_imc(70, 1.75)

💡 Vantagens dos módulos:

  • Organização: Cada arquivo tem uma responsabilidade
  • Reutilização: Use o mesmo módulo em vários projetos
  • Manutenção: Mais fácil encontrar e corrigir problemas
  • Colaboração: Várias pessoas podem trabalhar em arquivos diferentes

11.4 Criando seu Primeiro Módulo

Vamos criar um módulo simples para cálculos matemáticos!

11.4.1 Passo 1: Criar o arquivo do módulo

Primeiro, vamos criar um arquivo chamado matematica.py:

# matematica.py - Nosso primeiro módulo!

def somar(a, b):
    """Soma dois números"""
    return a + b

def subtrair(a, b):
    """Subtrai dois números"""
    return a - b

def multiplicar(a, b):
    """Multiplica dois números"""
    return a * b

def dividir(a, b):
    """Divide dois números"""
    if b != 0:
        return a / b
    else:
        return "Erro: Divisão por zero!"

def potencia(base, expoente):
    """Calcula base elevada ao expoente"""
    return base ** expoente

# Constantes úteis
PI = 3.14159265359
E = 2.71828182846

print("Módulo matematica.py carregado!")

11.4.2 Passo 2: Usar o módulo em outro arquivo

Agora vamos criar um arquivo calculadora.py que usa nosso módulo:

# calculadora.py - Usando nosso módulo matematica

# Importar o módulo inteiro
import matematica

# Usar as funções do módulo
resultado1 = matematica.somar(10, 5)
resultado2 = matematica.multiplicar(3, 4)
resultado3 = matematica.potencia(2, 3)

print(f"10 + 5 = {resultado1}")
print(f"3 × 4 = {resultado2}")
print(f"2³ = {resultado3}")
print(f"Valor de PI = {matematica.PI}")

11.4.3 Passo 3: Executar e ver o resultado

Quando você executar calculadora.py, verá:

Módulo matematica.py carregado!
10 + 5 = 15
3 × 4 = 12
2³ = 8
Valor de PI = 3.14159265359

💡 O que aconteceu? 1. Python encontrou o arquivo matematica.py 2. Executou todo o código do módulo (por isso apareceu “Módulo matematica.py carregado!”) 3. Disponibilizou as funções e variáveis para uso 4. Nosso programa principal usou as funções normalmente

11.5 Diferentes Formas de Importar

Existem várias maneiras de importar módulos. Cada uma tem suas vantagens!

11.5.1 Forma 1: import modulo (Importar tudo)

import matematica

# Usar com o nome do módulo
resultado = matematica.somar(5, 3)
print(f"PI = {matematica.PI}")

Vantagens:

  • ✅ Sempre sabe de onde vem a função
  • ✅ Evita conflitos de nomes
  • ✅ Mais claro e explícito

Desvantagens:

  • ❌ Mais verboso (tem que escrever matematica. sempre)

11.5.2 Forma 2: from modulo import funcao (Importar específico)

from matematica import somar, multiplicar, PI

# Usar diretamente, sem o nome do módulo
resultado = somar(5, 3)
print(f"PI = {PI}")

Vantagens:

  • ✅ Mais limpo e direto
  • ✅ Não precisa escrever o nome do módulo

Desvantagens:

  • ❌ Pode causar conflitos se importar muitas coisas
  • ❌ Menos claro de onde vem a função

11.5.3 Forma 3: import modulo as apelido (Importar com apelido)

import matematica as math

# Usar com o apelido
resultado = math.somar(5, 3)
print(f"PI = {math.PI}")

Vantagens:

  • ✅ Nome mais curto
  • ✅ Evita conflitos com nomes existentes
  • ✅ Mais legível

11.5.4 Forma 4: from modulo import * (Importar tudo - CUIDADO!)

from matematica import *

# Usar diretamente
resultado = somar(5, 3)
print(f"PI = {PI}")

⚠️ CUIDADO: Esta forma pode causar problemas! Evite usar import * em projetos grandes.

11.5.5 Comparação Prática

# Forma 1: Mais explícita
import matematica
print(matematica.somar(2, 3))

# Forma 2: Mais direta
from matematica import somar
print(somar(2, 3))

# Forma 3: Mais concisa
import matematica as m
print(m.somar(2, 3))

# Forma 4: Mais perigosa
from matematica import *
print(somar(2, 3))

💡 Recomendação: Use a Forma 1 (import modulo) para projetos pequenos e a Forma 2 (from modulo import funcao) quando souber exatamente o que precisa!

11.6 A Variável __name__ - O Guardião dos Módulos

11.6.1 O Problema

Imagine que você tem um módulo matematica.py que faz cálculos, mas também tem um código de teste no final:

# matematica.py
def somar(a, b):
    return a + b

def multiplicar(a, b):
    return a * b

# Código de teste (problema!)
print("Testando o módulo...")
print(f"2 + 3 = {somar(2, 3)}")
print(f"4 × 5 = {multiplicar(4, 5)}")

Problema: Toda vez que alguém importar seu módulo, esse código de teste vai executar! 😱

11.6.2 A Solução: if __name__ == "__main__"

A variável __name__ é especial em Python:

  • Quando o arquivo é executado diretamente: __name__ == "__main__"
  • Quando o arquivo é importado: __name__ == "nome_do_modulo"
# matematica.py - Versão corrigida!
def somar(a, b):
    return a + b

def multiplicar(a, b):
    return a * b

# Código de teste só executa quando rodamos o arquivo diretamente
if __name__ == "__main__":
    print("Testando o módulo...")
    print(f"2 + 3 = {somar(2, 3)}")
    print(f"4 × 5 = {multiplicar(4, 5)}")

11.6.3 Testando na Prática

Cenário 1: Executar matematica.py diretamente

python matematica.py

Saída:

Testando o módulo...
2 + 3 = 5
4 × 5 = 20

Cenário 2: Importar o módulo em outro arquivo

# calculadora.py
import matematica

resultado = matematica.somar(10, 5)
print(f"10 + 5 = {resultado}")

Saída:

10 + 5 = 15

(Sem os prints de teste!)

11.6.4 Analogia Perfeita

Pense em um livro de receitas:

  • 📖 Quando você abre o livro para ler: Você vê as receitas, mas não cozinha automaticamente
  • 👨‍🍳 Quando você quer testar uma receita: Você vai para a cozinha e faz a receita

if __name__ == "__main__" é como dizer: “Só cozinhe quando eu estiver testando a receita, não quando alguém estiver apenas lendo o livro!”

💡 Regra de Ouro: Sempre use if __name__ == "__main__" quando tiver código de teste ou demonstração no final do seu módulo!

11.7 Bibliotecas Built-in - O que já vem com Python

Python já vem com muitas bibliotecas úteis! É como ter uma cozinha equipada desde o início. Vamos conhecer as principais:

11.7.1 datetime - Trabalhando com Datas e Horas

import datetime

# Data e hora atual
agora = datetime.datetime.now()
print(f"Agora são: {agora}")

# Data específica
nascimento = datetime.date(1990, 5, 15)
print(f"Nascimento: {nascimento}")

# Calcular idade
hoje = datetime.date.today()
idade = hoje - nascimento
print(f"Você tem {idade.days} dias de vida!")

# Formatar data
print(f"Data formatada: {agora.strftime('%d/%m/%Y %H:%M')}")

11.7.2 random - Números Aleatórios

import random

# Número aleatório entre 1 e 10
numero = random.randint(1, 10)
print(f"Número aleatório: {numero}")

# Escolher item aleatório de uma lista
frutas = ["maçã", "banana", "laranja", "uva"]
fruta_escolhida = random.choice(frutas)
print(f"Fruta sorteada: {fruta_escolhida}")

# Embaralhar lista
cartas = ["Ás", "Rei", "Dama", "Valete"]
random.shuffle(cartas)
print(f"Cartas embaralhadas: {cartas}")

# Número decimal aleatório entre 0 e 1
decimal = random.random()
print(f"Número decimal: {decimal}")

11.7.3 math - Operações Matemáticas Avançadas

import math

# Constantes matemáticas
print(f"PI = {math.pi}")
print(f"E = {math.e}")

# Funções matemáticas
print(f"Raiz quadrada de 16: {math.sqrt(16)}")
print(f"2 elevado a 8: {math.pow(2, 8)}")
print(f"Logaritmo de 100: {math.log10(100)}")
print(f"Seno de 90 graus: {math.sin(math.radians(90))}")

# Arredondamentos
numero = 3.7
print(f"Arredondar para cima: {math.ceil(numero)}")
print(f"Arredondar para baixo: {math.floor(numero)}")

11.7.4 os - Interagindo com o Sistema Operacional

import os

# Informações do sistema
print(f"Sistema operacional: {os.name}")
print(f"Diretório atual: {os.getcwd()}")

# Listar arquivos do diretório atual
arquivos = os.listdir('.')
print(f"Arquivos no diretório: {arquivos}")

# Criar diretório
os.makedirs('meu_diretorio', exist_ok=True)
print("Diretório criado!")

# Verificar se arquivo existe
if os.path.exists('README.md'):
    print("README.md existe!")
else:
    print("README.md não encontrado!")

11.7.5 pathlib - Manipulação Moderna de Caminhos

from pathlib import Path

# Criar objeto Path
arquivo = Path('documentos/relatorio.txt')

# Informações do arquivo
print(f"Nome do arquivo: {arquivo.name}")
print(f"Extensão: {arquivo.suffix}")
print(f"Diretório pai: {arquivo.parent}")

# Criar diretório se não existir
arquivo.parent.mkdir(parents=True, exist_ok=True)

# Verificar se existe
if arquivo.exists():
    print("Arquivo existe!")
else:
    print("Arquivo não existe!")

# Listar arquivos Python no diretório atual
python_files = list(Path('.').glob('*.py'))
print(f"Arquivos Python: {python_files}")

💡 Dica: pathlib é mais moderno que os.path. Use pathlib para novos projetos!

11.8 Módulo collections - Ferramentas Avançadas para Coleções

📌 Quando ler esta seção: Esta seção é importante para resolver exercícios de níveis 4-5. O módulo collections oferece ferramentas poderosas para trabalhar com coleções de dados.

11.8.1 O que é o módulo collections?

O módulo collections do Python oferece ferramentas especializadas para trabalhar com diferentes tipos de coleções de dados. Uma das mais úteis é o Counter.

11.8.2 Importando Counter

from collections import Counter

11.8.3 Counter - Contando Elementos

O Counter é uma subclasse de dicionário especializada em contar elementos. É perfeito para:

  • Contar frequência de elementos em uma lista
  • Encontrar elementos mais comuns
  • Comparar distribuições de dados

11.8.4 Exemplos Práticos

11.8.4.1 1. Contar letras em uma palavra

from collections import Counter

palavra = "python"
contador = Counter(palavra)
print(contador)
# Resultado: Counter({'p': 1, 'y': 1, 't': 1, 'h': 1, 'o': 1, 'n': 1})

11.8.4.2 2. Contar números em uma lista

from collections import Counter

numeros = [1, 2, 3, 2, 1, 3, 3, 1, 2, 1]
contador = Counter(numeros)
print(contador)
# Resultado: Counter({1: 4, 2: 3, 3: 3})

11.8.4.3 3. Contar palavras em uma frase

from collections import Counter

frase = "python é uma linguagem python é poderosa"
palavras = frase.split()
contador = Counter(palavras)
print(contador)
# Resultado: Counter({'python': 2, 'é': 2, 'uma': 1, 'linguagem': 1, 'poderosa': 1})

11.8.5 Métodos Úteis do Counter

11.8.5.1 1. most_common(n) - Encontrar elementos mais comuns

from collections import Counter

dados = [1, 2, 3, 2, 1, 3, 3, 1, 2, 1, 3, 3, 3]
contador = Counter(dados)

# Os 3 mais comuns
print(contador.most_common(3))
# Resultado: [(3, 5), (1, 4), (2, 3)]

# O mais comum
print(contador.most_common(1))
# Resultado: [(3, 5)]

11.8.5.2 2. Acessar contagens individuais

from collections import Counter

numeros = [1, 2, 3, 2, 1, 3]
contador = Counter(numeros)

print(f"Número 1 aparece {contador[1]} vezes")
print(f"Número 2 aparece {contador[2]} vezes")
print(f"Número 3 aparece {contador[3]} vezes")
print(f"Número 4 aparece {contador[4]} vezes")  # Retorna 0 se não existir

11.8.5.3 3. Operações matemáticas

from collections import Counter

# Counter 1
dados1 = [1, 2, 3, 2, 1]
contador1 = Counter(dados1)

# Counter 2
dados2 = [2, 3, 4, 3, 2]
contador2 = Counter(dados2)

# Somar counters
soma = contador1 + contador2
print("Soma:", soma)
# Resultado: Counter({2: 4, 3: 3, 1: 2, 4: 1})

# Subtrair counters
diferenca = contador1 - contador2
print("Diferença:", diferenca)
# Resultado: Counter({1: 2})

11.8.6 Exemplos dos Exercícios

Muitos exercícios usam Counter. Aqui estão exemplos:

# Exemplo do exercício de análise de dados
from collections import Counter

# Simular lançamentos de dados
import random
lancamentos = [random.randint(1, 6) for _ in range(100)]
frequencia = Counter(lancamentos)

print("Frequência dos lançamentos:")
for face, count in sorted(frequencia.items()):
    print(f"Face {face}: {count} vezes")

# Exemplo do exercício de análise de texto
texto = "python é uma linguagem incrível python é fácil de aprender"
palavras = texto.split()
contador_palavras = Counter(palavras)

print("Palavras mais comuns:")
for palavra, count in contador_palavras.most_common(3):
    print(f"'{palavra}': {count} vezes")

11.8.7 Outras Classes do módulo collections

11.8.7.1 1. defaultdict - Dicionário com valores padrão

from collections import defaultdict

# Lista vazia como valor padrão
dd = defaultdict(list)
dd['frutas'].append('maçã')
dd['frutas'].append('banana')
print(dd['frutas'])  # ['maçã', 'banana']
print(dd['legumes'])  # [] (lista vazia, não erro!)

11.8.7.2 2. deque - Lista com operações eficientes nas extremidades

from collections import deque

# Criar uma deque
fila = deque([1, 2, 3])

# Adicionar no final
fila.append(4)

# Adicionar no início
fila.appendleft(0)

# Remover do início (eficiente!)
primeiro = fila.popleft()
print(fila)  # deque([1, 2, 3, 4])

11.8.8 Dicas Importantes

  1. Use Counter quando precisar contar frequências
  2. Use most_common() para encontrar elementos mais comuns
  3. Counter funciona com qualquer iterável (listas, strings, tuplas)
  4. Counter herda de dict, então você pode usar métodos de dicionário

11.8.9 Quando Usar Counter

Use Counter quando: - ✅ Precisar contar frequências de elementos - ✅ Quiser encontrar elementos mais comuns - ✅ Estiver analisando distribuições de dados - ✅ Quiser comparar duas coleções

Exemplos práticos: - Análise de texto (contar palavras) - Análise de dados (contar ocorrências) - Jogos (contar resultados) - Estatísticas (distribuições)

💡 Dica: Counter é uma ferramenta muito poderosa para análise de dados. Muitos exercícios avançados usam ela para resolver problemas de contagem e frequência!

11.9 Estruturas de Dados Complexas - Dicionários e Listas Aninhadas

📌 Quando ler esta seção: Esta seção é importante para exercícios de níveis 4-5. Python permite criar estruturas de dados complexas combinando listas e dicionários.

11.9.1 O que são Estruturas Aninhadas?

Estruturas aninhadas são estruturas de dados que contêm outras estruturas dentro delas. É como ter “caixas dentro de caixas” - você pode ter listas dentro de dicionários, dicionários dentro de listas, e assim por diante.

11.9.2 Dicionários Aninhados

11.9.2.1 Estrutura básica

# Dicionário com dicionários dentro
empresa = {
    "nome": "Tech Corp",
    "endereco": {
        "rua": "Rua das Flores, 123",
        "cidade": "São Paulo",
        "cep": "01234-567"
    },
    "contato": {
        "telefone": "(11) 99999-9999",
        "email": "contato@techcorp.com"
    }
}

# Acessando dados aninhados
print(empresa["nome"])                    # "Tech Corp"
print(empresa["endereco"]["cidade"])      # "São Paulo"
print(empresa["contato"]["email"])        # "contato@techcorp.com"

11.9.2.2 Exemplo prático: Sistema de biblioteca

biblioteca = {
    "nome": "Biblioteca Central",
    "livros": [
        {
            "titulo": "Python para Iniciantes",
            "autor": "João Silva",
            "ano": 2023,
            "disponivel": True,
            "categoria": "Programação"
        },
        {
            "titulo": "Algoritmos e Estruturas de Dados",
            "autor": "Maria Santos",
            "ano": 2022,
            "disponivel": False,
            "categoria": "Ciência da Computação"
        }
    ],
    "usuarios": {
        "001": {
            "nome": "Ana Costa",
            "email": "ana@email.com",
            "livros_emprestados": ["Python para Iniciantes"]
        },
        "002": {
            "nome": "Carlos Oliveira",
            "email": "carlos@email.com",
            "livros_emprestados": []
        }
    }
}

# Acessando dados
print(f"Biblioteca: {biblioteca['nome']}")
print(f"Primeiro livro: {biblioteca['livros'][0]['titulo']}")
print(f"Usuário 001: {biblioteca['usuarios']['001']['nome']}")

11.9.3 Listas de Dicionários

11.9.3.1 Estrutura básica

# Lista contendo dicionários
funcionarios = [
    {
        "nome": "João",
        "cargo": "Desenvolvedor",
        "salario": 5000,
        "departamento": "TI"
    },
    {
        "nome": "Maria",
        "cargo": "Designer",
        "salario": 4500,
        "departamento": "Design"
    },
    {
        "nome": "Pedro",
        "cargo": "Gerente",
        "salario": 7000,
        "departamento": "Administração"
    }
]

# Acessando dados
print(funcionarios[0]["nome"])        # "João"
print(funcionarios[1]["salario"])     # 4500
print(funcionarios[2]["departamento"]) # "Administração"

11.9.4 Manipulando Estruturas Complexas

11.9.4.1 1. Filtrar dados

# Filtrar funcionários do departamento TI
funcionarios_ti = [f for f in funcionarios if f["departamento"] == "TI"]
print("Funcionários de TI:")
for func in funcionarios_ti:
    print(f"- {func['nome']}: {func['cargo']}")

11.9.4.2 2. Buscar informações específicas

# Encontrar funcionário por nome
def encontrar_funcionario(nome):
    for func in funcionarios:
        if func["nome"] == nome:
            return func
    return None

joao = encontrar_funcionario("João")
if joao:
    print(f"João trabalha como {joao['cargo']} ganhando R$ {joao['salario']}")

11.9.4.3 3. Calcular estatísticas

# Calcular salário médio por departamento
departamentos = {}
for func in funcionarios:
    dept = func["departamento"]
    if dept not in departamentos:
        departamentos[dept] = []
    departamentos[dept].append(func["salario"])

print("Salário médio por departamento:")
for dept, salarios in departamentos.items():
    media = sum(salarios) / len(salarios)
    print(f"{dept}: R$ {media:.2f}")

11.9.5 Exemplos dos Exercícios

Muitos exercícios usam estruturas complexas. Aqui estão exemplos:

11.9.5.1 Exemplo 1: Sistema de hotel

hotel = {
    "nome": "Hotel Python",
    "quartos": [
        {"numero": "101", "tipo": "Simples", "preco": 150, "disponivel": True},
        {"numero": "102", "tipo": "Duplo", "preco": 200, "disponivel": False},
        {"numero": "201", "tipo": "Suíte", "preco": 350, "disponivel": True}
    ],
    "reservas": []
}

# Quartos disponíveis
quartos_disponiveis = [q for q in hotel["quartos"] if q["disponivel"]]
print("Quartos disponíveis:")
for quarto in quartos_disponiveis:
    print(f"- Quarto {quarto['numero']}: {quarto['tipo']} - R$ {quarto['preco']}")

11.9.5.2 Exemplo 2: Sistema de vendas

vendas = [
    {"produto": "Notebook", "quantidade": 2, "preco_unitario": 2500, "cliente": "João"},
    {"produto": "Mouse", "quantidade": 5, "preco_unitario": 50, "cliente": "Maria"},
    {"produto": "Teclado", "quantidade": 3, "preco_unitario": 120, "cliente": "João"}
]

# Calcular total por cliente
total_por_cliente = {}
for venda in vendas:
    cliente = venda["cliente"]
    total = venda["quantidade"] * venda["preco_unitario"]
    
    if cliente not in total_por_cliente:
        total_por_cliente[cliente] = 0
    total_por_cliente[cliente] += total

print("Total por cliente:")
for cliente, total in total_por_cliente.items():
    print(f"{cliente}: R$ {total:,.2f}")

11.9.6 Dicas Importantes

  1. Use chaves consistentes nos dicionários
  2. Acesse dados aninhados com múltiplos colchetes: dados["chave1"]["chave2"]
  3. Use list comprehensions para filtrar estruturas complexas
  4. Valide se as chaves existem antes de acessá-las

11.9.7 Quando Usar Estruturas Complexas

Use quando: - ✅ Precisar organizar dados relacionados - ✅ Quiser criar sistemas mais realistas - ✅ Estiver trabalhando com dados hierárquicos - ✅ Quiser simular estruturas de banco de dados

Exemplos práticos: - Sistemas de gerenciamento - APIs com dados complexos - Simulação de bancos de dados - Organização de informações relacionadas

💡 Dica: Estruturas aninhadas são fundamentais para criar programas mais realistas e organizados. Elas permitem representar dados complexos de forma estruturada!

📌 Nota sobre Análise de Texto Avançada: Para análise avançada de texto, validação de formatos complexos e extração de informações usando expressões regulares, consulte o Capítulo 16 - Expressões Regulares. Este capítulo cobre em profundidade todas as técnicas de busca e manipulação de texto com regex.

11.10 Instalando Bibliotecas Externas com pip

11.10.1 O que é pip?

pip é o gerenciador de pacotes do Python. É como uma loja online de ingredientes para sua cozinha de programação!

  • 🏪 PyPI (Python Package Index): A “loja” onde ficam todas as bibliotecas
  • 📦 pip: O “entregador” que baixa e instala as bibliotecas
  • 🍰 Bibliotecas: Os “ingredientes” prontos para usar

11.10.2 Como instalar bibliotecas

# Instalar uma biblioteca
pip install nome_da_biblioteca

# Exemplos práticos
pip install requests      # Para fazer requisições HTTP
pip install beautifulsoup4  # Para web scraping
pip install flask        # Para criar APIs web
pip install pandas       # Para análise de dados
pip install matplotlib   # Para gráficos

11.10.3 Exemplo Prático: Instalando requests

Vamos instalar a biblioteca requests para fazer requisições HTTP:

pip install requests

Depois podemos usar:

import requests

# Fazer uma requisição GET
response = requests.get('https://api.github.com/users/octocat')
print(f"Status: {response.status_code}")
print(f"Dados: {response.json()}")

11.10.4 Gerenciando Dependências com requirements.txt

Para projetos maiores, é boa prática criar um arquivo requirements.txt:

# requirements.txt
requests==2.28.1
beautifulsoup4==4.11.1
flask==2.2.2
pandas==1.5.2
matplotlib==3.6.2

Depois instalar tudo de uma vez:

pip install -r requirements.txt

11.10.5 Comandos Úteis do pip

# Listar bibliotecas instaladas
pip list

# Mostrar informações de uma biblioteca
pip show requests

# Atualizar uma biblioteca
pip install --upgrade requests

# Desinstalar uma biblioteca
pip uninstall requests

# Instalar versão específica
pip install requests==2.28.1

# Instalar em modo desenvolvimento (para desenvolvimento)
pip install -e .

11.10.6 Ambientes Virtuais (Bônus)

Para evitar conflitos entre projetos, use ambientes virtuais:

# Criar ambiente virtual
python -m venv meu_projeto

# Ativar ambiente virtual (Windows)
meu_projeto\\Scripts\\activate

# Ativar ambiente virtual (Linux/Mac)
source meu_projeto/bin/activate

# Instalar bibliotecas no ambiente virtual
pip install requests

# Desativar ambiente virtual
deactivate

💡 Dica: Sempre use ambientes virtuais para projetos separados! É como ter cozinhas diferentes para cada tipo de receita!

11.11 Exercícios Práticos (respostas no final da página)

🚀 Hora de praticar! Aqui estão 25 exercícios organizados por dificuldade. Cada exercício tem solução completa com explicação linha por linha!

11.11.1 MUITO FÁCIL (Nível 1)

1. Módulo de Cumprimentos Crie um módulo chamado cumprimentos.py com uma função dizer_oi() que retorna “Olá!”.

  • Exemplo: Output → "Olá!"

2. Teste do Módulo Crie um arquivo teste_cumprimentos.py que importa e usa a função do exercício anterior.

  • Exemplo: Input → import cumprimentos | Output → "Olá!"

3. Número Aleatório Use a biblioteca random para sortear um número entre 1 e 100.

  • Exemplo: Output → Número sorteado: 42

4. Data Atual Use a biblioteca datetime para mostrar a data atual no formato brasileiro (dd/mm/aaaa).

  • Exemplo: Output → Data atual: 15/01/2024

5. Raiz Quadrada Use a biblioteca math para calcular a raiz quadrada de 144.

  • Exemplo: Output → Raiz quadrada de 144: 12.0

11.11.2 FÁCIL (Nível 2)

6. Calculadora Avançada Crie um módulo calculadora_avancada.py com funções para calcular área de círculo, retângulo e triângulo.

  • Exemplo: Input → raio=5 | Output → Área do círculo: 78.54

7. Validadores Crie um módulo validadores.py com funções para validar email, CPF e telefone (apenas estrutura básica).

  • Exemplo: Input → "teste@email.com" | Output → Email válido: True

8. Sorteio de Brindes Use random.choice() para criar um sorteio de brindes entre uma lista de 5 itens.

  • Exemplo: Input → ["Caneta", "Caderno", "Camiseta", "Livro", "Mousepad"] | Output → Brinde sorteado: Caneta

9. Dias para Aniversário Use datetime para calcular quantos dias faltam para o seu aniversário.

  • Exemplo: Input → nascimento: 15/05/1990 | Output → Dias para o próximo aniversário: 120

10. Listar Arquivos Use os.listdir() para listar todos os arquivos .txt do diretório atual.

  • Exemplo: Output → Arquivos .txt encontrados: ['arquivo1.txt', 'arquivo2.txt']

11.11.3 MÉDIO (Nível 3)

11. Gerador de Senhas Crie um módulo gerador_senhas.py que gera senhas aleatórias com diferentes níveis de segurança.

  • Exemplo: Input → nivel="alto" | Output → Senha gerada: A7bK9mP2

12. Conversor de Moedas Crie um módulo conversor_moedas.py que converte entre Real, Dólar e Euro (use valores fictícios).

  • Exemplo: Input → 100, "BRL", "USD" | Output → R$ 100.00 = $ 18.50

13. Estrutura de Diretórios Use pathlib para criar uma estrutura de diretórios: projetos/python/exercicios/.

  • Exemplo: Output → Estrutura criada: projetos/python/exercicios/

14. Estatísticas Crie um módulo estatisticas.py que calcula média, mediana e moda de uma lista de números.

  • Exemplo: Input → [1, 2, 3, 3, 4, 5] | Output → Média: 3.0, Mediana: 3.0, Moda: 3

15. Embaralhar Cartas Use random.shuffle() para embaralhar uma lista de cartas de baralho.

  • Exemplo: Input → ["Ás", "Rei", "Dama", "Valete"] | Output → ["Dama", "Ás", "Valete", "Rei"]

11.11.4 DIFÍCIL (Nível 4)

16. Agenda de Contatos Crie um módulo agenda.py que gerencia contatos com funções de adicionar, remover, buscar e listar.

  • Exemplo: Input → adicionar: "João", "11999999999" | Output → Contato adicionado: João - 11999999999

17. Jogo de Adivinhação Crie um módulo jogo_adivinhacao.py que implementa um jogo completo de adivinhar números.

  • Exemplo: Input → tentar: 50 | Output → Muito alto! Tente um número menor.

18. Gerador de Datas Use datetime e random para criar um gerador de datas aleatórias dentro de um período específico.

  • Exemplo: Input → 2024-01-01 até 2024-12-31 | Output → Data aleatória: 2024-06-15

19. Organizador de Arquivos Crie um módulo arquivo_utils.py que organiza arquivos por extensão em diretórios separados.

  • Exemplo: Input → arquivos: [a.txt, b.pdf, c.jpg] | Output → Arquivos organizados por extensão!

20. Calculadora Científica Crie um módulo calculadora_cientifica.py com funções trigonométricas, logarítmicas e exponenciais.

  • Exemplo: Input → sen(90) | Output → Seno de 90°: 1.0

11.11.5 MUITO DIFÍCIL (Nível 5)

21. Sistema de Biblioteca Crie um sistema modular completo de gerenciamento de biblioteca com módulos separados para livros, usuários e empréstimos.

  • Exemplo: Input → emprestar livro, usuário | Output → Livro emprestado com sucesso!

22. Criptografia Implemente um módulo crypto.py que criptografa e descriptografa textos usando cifra de César.

  • Exemplo: Input → "Python", chave=3 | Output → Texto criptografado: Sbwkrq

23. Simulador de Dados Crie um módulo simulador_dados.py que simula lançamentos de dados com diferentes tipos e probabilidades.

  • Exemplo: Input → dado de 6 faces, 100 lançamentos | Output → Frequência: {1: 16, 2: 18, 3: 15, 4: 17, 5: 16, 6: 18}

24. Analisador de Texto Implemente um módulo analisador_texto.py que analisa frequência de palavras, sentimento e estatísticas de texto.

  • Exemplo: Input → "Python é uma linguagem incrível" | Output → Palavras: 5, Caracteres: 35, Palavra mais comum: Python

25. Gerenciador de Projetos Crie um módulo gerenciador_projetos.py que organiza projetos em diretórios com templates e estruturas padronizadas.

  • Exemplo: Input → criar projeto "meu_app" | Output → Projeto 'meu_app' criado com estrutura padrão!

11.12 Respostas e Explicações

11.12.1 MUITO FÁCIL (Nível 1)

1. Módulo de Cumprimentos

# cumprimentos.py
def dizer_oi():
    return "Olá!"

def dizer_tchau():
    return "Tchau!"

if __name__ == "__main__":
    print(dizer_oi())

Explicação linha por linha:

  • Linha 1: # cumprimentos.py - Comentário indicando nome do arquivo
  • Linha 2: def dizer_oi(): - Define função que retorna cumprimento
  • Linha 3: return "Olá!" - Retorna string com cumprimento
  • Linha 5: def dizer_tchau(): - Define função adicional para despedida
  • Linha 6: return "Tchau!" - Retorna string com despedida
  • Linha 8: if __name__ == "__main__": - Verifica se arquivo está sendo executado diretamente
  • Linha 9: print(dizer_oi()) - Chama função e mostra resultado quando executado diretamente

2. Teste do Módulo

# teste_cumprimentos.py
import cumprimentos

mensagem = cumprimentos.dizer_oi()
print(mensagem)

Explicação linha por linha:

  • Linha 1: # teste_cumprimentos.py - Comentário indicando nome do arquivo
  • Linha 2: import cumprimentos - Importa o módulo cumprimentos criado anteriormente
  • Linha 4: mensagem = cumprimentos.dizer_oi() - Chama função do módulo e armazena resultado
  • Linha 5: print(mensagem) - Mostra a mensagem retornada pela função

3. Número Aleatório

import random

numero_sorteado = random.randint(1, 100)
print(f"Número sorteado: {numero_sorteado}")

Explicação linha por linha:

  • Linha 1: import random - Importa módulo random para gerar números aleatórios
  • Linha 3: numero_sorteado = random.randint(1, 100) - Gera número inteiro aleatório entre 1 e 100
  • Linha 4: print(f"Número sorteado: {numero_sorteado}") - Mostra número sorteado formatado

4. Data Atual

import datetime

agora = datetime.datetime.now()
data_brasileira = agora.strftime('%d/%m/%Y')
print(f"Data atual: {data_brasileira}")

Explicação linha por linha:

  • Linha 1: import datetime - Importa módulo datetime para trabalhar com datas
  • Linha 3: agora = datetime.datetime.now() - Obtém data e hora atuais
  • Linha 4: data_brasileira = agora.strftime('%d/%m/%Y') - Formata data no padrão brasileiro (dia/mês/ano)
  • Linha 5: print(f"Data atual: {data_brasileira}") - Mostra data formatada

5. Raiz Quadrada

import math

raiz = math.sqrt(144)
print(f"Raiz quadrada de 144: {raiz}")

Explicação linha por linha:

  • Linha 1: import math - Importa módulo math para operações matemáticas
  • Linha 3: raiz = math.sqrt(144) - Calcula raiz quadrada de 144 usando função sqrt()
  • Linha 4: print(f"Raiz quadrada de 144: {raiz}") - Mostra resultado do cálculo

11.12.2 DIFÍCIL (Nível 4)

16. Agenda de Contatos

# agenda.py

contatos = {}

def adicionar_contato(nome, telefone):
    """Adiciona um novo contato à agenda"""
    contatos[nome] = telefone
    return f"Contato adicionado: {nome} - {telefone}"

def remover_contato(nome):
    """Remove um contato da agenda"""
    if nome in contatos:
        telefone = contatos.pop(nome)
        return f"Contato removido: {nome} - {telefone}"
    else:
        return f"Contato '{nome}' não encontrado!"

def buscar_contato(nome):
    """Busca um contato na agenda"""
    if nome in contatos:
        return f"Contato encontrado: {nome} - {contatos[nome]}"
    else:
        return f"Contato '{nome}' não encontrado!"

def listar_contatos():
    """Lista todos os contatos da agenda"""
    if not contatos:
        return "Agenda vazia!"
    
    lista = "CONTATOS:\n"
    for nome, telefone in contatos.items():
        lista += f"- {nome}: {telefone}\n"
    return lista.strip()

if __name__ == "__main__":
    print(adicionar_contato("João", "11999999999"))
    print(adicionar_contato("Maria", "11888888888"))
    print(buscar_contato("João"))
    print(listar_contatos())

Explicação linha por linha:

  • Linha 1: # agenda.py - Comentário indicando nome do arquivo
  • Linha 3: contatos = {} - Cria dicionário vazio para armazenar contatos
  • Linha 5: def adicionar_contato(nome, telefone): - Define função para adicionar contato
  • Linha 6: """Adiciona um novo contato à agenda""" - Docstring da função
  • Linha 7: contatos[nome] = telefone - Adiciona contato ao dicionário usando nome como chave
  • Linha 8: return f"Contato adicionado: {nome} - {telefone}" - Retorna mensagem de confirmação
  • Linha 10: def remover_contato(nome): - Define função para remover contato
  • Linha 11: """Remove um contato da agenda""" - Docstring da função
  • Linha 12: if nome in contatos: - Verifica se contato existe no dicionário
  • Linha 13: telefone = contatos.pop(nome) - Remove contato e armazena telefone
  • Linha 14: return f"Contato removido: {nome} - {telefone}" - Retorna mensagem de confirmação

17. Jogo de Adivinhação

# jogo_adivinhacao.py
import random

def jogar_adivinhacao():
    """Implementa um jogo completo de adivinhar números"""
    numero_secreto = random.randint(1, 100)
    tentativas = 0
    max_tentativas = 7
    
    print("🎯 Jogo de Adivinhação!")
    print(f"Tente adivinhar um número entre 1 e 100. Você tem {max_tentativas} tentativas!")
    
    while tentativas < max_tentativas:
        try:
            palpite = int(input("Digite seu palpite: "))
            tentativas += 1
            
            if palpite == numero_secreto:
                print(f"🎉 Parabéns! Você acertou em {tentativas} tentativas!")
                return True
            elif palpite < numero_secreto:
                print("📈 Muito baixo! Tente um número maior.")
            else:
                print("📉 Muito alto! Tente um número menor.")
                
            print(f"Tentativas restantes: {max_tentativas - tentativas}")
            
        except ValueError:
            print("❌ Por favor, digite um número válido!")
            tentativas -= 1
    
    print(f"😞 Game Over! O número era {numero_secreto}")
    return False

if __name__ == "__main__":
    jogar_adivinhacao()

Explicação linha por linha:

  • Linha 1: # jogo_adivinhacao.py - Comentário indicando nome do arquivo
  • Linha 2: import random - Importa módulo random para gerar número secreto
  • Linha 4: def jogar_adivinhacao(): - Define função principal do jogo
  • Linha 5: """Implementa um jogo completo de adivinhar números""" - Docstring da função
  • Linha 6: numero_secreto = random.randint(1, 100) - Gera número aleatório entre 1 e 100
  • Linha 7: tentativas = 0 - Inicializa contador de tentativas
  • Linha 8: max_tentativas = 7 - Define número máximo de tentativas
  • Linha 10: print("🎯 Jogo de Adivinhação!") - Mostra título do jogo
  • Linha 11: print(f"Tente adivinhar um número entre 1 e 100. Você tem {max_tentativas} tentativas!") - Explica regras
  • Linha 13: while tentativas < max_tentativas: - Loop principal do jogo
  • Linha 15: path = int(input("Digite seu palpite: ")) - Solicita palpite do usuário

18. Gerador de Datas

# gerador_datas.py
import datetime
import random

def gerar_data_aleatoria(data_inicio, data_fim):
    """Gera uma data aleatória entre duas datas"""
    inicio = datetime.datetime.strptime(data_inicio, "%Y-%m-%d")
    fim = datetime.datetime.strptime(data_fim, "%Y-%m-%d")
    
    diferenca = (fim - inicio).days
    dias_aleatorios = random.randint(0, diferenca)
    
    data_aleatoria = inicio + datetime.timedelta(days=dias_aleatorios)
    return data_aleatoria.strftime("%Y-%m-%d")

if __name__ == "__main__":
    data_aleatoria = gerar_data_aleatoria("2024-01-01", "2024-12-31")
    print(f"Data aleatória: {data_aleatoria}")

Explicação linha por linha:

  • Linha 1: # gerador_datas.py - Comentário indicando nome do arquivo
  • Linha 2: import datetime - Importa módulo datetime para trabalhar com datas
  • Linha 3: import random - Importa módulo random para gerar números aleatórios
  • Linha 5: def gerar_data_aleatoria(data_inicio, data_fim): - Define função para gerar data aleatória
  • Linha 6: """Gera uma data aleatória entre duas datas""" - Docstring da função
  • Linha 7: inicio = datetime.datetime.strptime(data_inicio, "%Y-%m-%d") - Converte string para objeto datetime
  • Linha 8: fim = datetime.datetime.strptime(data_fim, "%Y-%m-%d") - Converte string para objeto datetime
  • Linha 10: q = (fim - inicio).days` - Calcula diferença em dias entre as datas
  • Linha 11: dias_aleatorios = random.randint(0, diferenca) - Gera número aleatório de dias
  • Linha 13: data_aleatoria = inicio + datetime.timedelta(days=dias_aleatorios) - Adiciona dias aleatórios à data inicial
  • Linha 14: return data_aleatoria.strftime("%Y-%m-%d") - Retorna data formatada como string

19. Organizador de Arquivos

# arquivo_utils.py
import os
from pathlib import Path

def organizar_arquivos(diretorio="."):
    """Organiza arquivos por extensão em diretórios separados"""
    diretorio_path = Path(diretorio)
    
    for arquivo in diretorio_path.iterdir():
        if arquivo.is_file():
            extensao = arquivo.suffix.lower()
            if extensao:
                pasta_destino = diretorio_path / extensao[1:]  # Remove o ponto da extensão
                pasta_destino.mkdir(exist_ok=True)
                arquivo.rename(pasta_destino / arquivo.name)
    
    print("Arquivos organizados por extensão!")

if __name__ == "__main__":
    organizar_arquivos()

Explicação linha por linha:

  • Linha 1: # arquivo_utils.py - Comentário indicando nome do arquivo
  • Linha 2: import os - Importa módulo os para operações do sistema
  • Linha 3: from pathlib import Path - Importa classe Path do módulo pathlib
  • Linha 5: def organizar_arquivos(diretorio="."): - Define função para organizar arquivos
  • Linha 6: """Organiza arquivos por extensão em diretórios separados""" - Docstring da função
  • Linha 7: diretorio_path = Path(diretorio) - Cria objeto Path com diretório especificado
  • Linha 9: for arquivo in diretorio_path.iterdir(): - Percorre todos os itens do diretório
  • Linha 10: if arquivo.is_file(): - Verifica se item é um arquivo
  • Linha 11: extensao = arquivo.suffix.lower() - Obtém extensão do arquivo em minúsculas
  • Linha 12: if extensao: - Verifica se arquivo tem extensão
  • Linha 13: pasta_destino = diretorio_path / extensao[1:] - Cria caminho para pasta de destino

20. Calculadora Científica

# calculadora_cientifica.py
import math

def seno(graus):
    """Calcula o seno de um ângulo em graus"""
    return math.sin(math.radians(graus))

def cosseno(graus):
    """Calcula o cosseno de um ângulo em graus"""
    return math.cos(math.radians(graus))

def tangente(graus):
    """Calcula a tangente de um ângulo em graus"""
    return math.tan(math.radians(graus))

def logaritmo(numero, base=10):
    """Calcula logaritmo de um número"""
    if base == 10:
        return math.log10(numero)
    elif base == math.e:
        return math.log(numero)
    else:
        return math.log(numero) / math.log(base)

def exponencial(expoente):
    """Calcula e elevado ao expoente"""
    return math.exp(expoente)

if __name__ == "__main__":
    print(f"Seno de 90°: {seno(90):.2f}")
    print(f"Cosseno de 0°: {cosseno(0):.2f}")
    print(f"Tangente de 45°: {tangente(45):.2f}")
    print(f"Logaritmo de 100: {logaritmo(100):.2f}")
    print(f"e elevado a 2: {exponencial(2):.2f}")

Explicação linha por linha:

  • Linha 1: # calculadora_cientifica.py - Comentário indicando nome do arquivo
  • Linha 2: import math - Importa módulo math para funções matemáticas
  • Linha 4: def seno(graus): - Define função para calcular seno
  • Linha 5: """Calcula o seno de um ângulo em graus""" - Docstring da função
  • Linha 6: return math.sin(math.radians(graus)) - Converte graus para radianos e calcula seno
  • Linha 8: def cosseno(graus): - Define função para calcular cosseno
  • Linha 9: """Calcula o cosseno de um ângulo em graus""" - Docstring da função
  • Linha 10: return math.cos(math.radians(graus)) - Converte graus para radianos e calcula cosseno
  • Linha 12: def tangente(graus): - Define função para calcular tangente
  • Linha 13: """Calcula a tangente de um ângulo em graus""" - Docstring da função
  • Linha 14: return math.tan(math.radians(graus)) - Converte graus para radianos e calcula tangente

11.12.3 MUITO DIFÍCIL (Nível 5)

21. Sistema de Biblioteca

# sistema_biblioteca.py
# Este é um sistema modular completo com múltiplos módulos

# Módulo: livros.py
livros = {}

def adicionar_livro(titulo, autor, isbn):
    """Adiciona um novo livro ao sistema"""
    livros[isbn] = {"titulo": titulo, "autor": autor, "disponivel": True}
    return f"Livro '{titulo}' adicionado com sucesso!"

def buscar_livro(isbn):
    """Busca um livro por ISBN"""
    if isbn in livros:
        return livros[isbn]
    return None

def emprestar_livro(isbn, usuario):
    """Empresta um livro para um usuário"""
    if isbn in livros and livros[isbn]["disponivel"]:
        livros[isbn]["disponivel"] = False
        livros[isbn]["usuario"] = usuario
        return f"Livro emprestado para {usuario}!"
    return "Livro não disponível!"

# Módulo: usuarios.py
usuarios = {}

def adicionar_usuario(nome, email, cpf):
    """Adiciona um novo usuário ao sistema"""
    usuarios[cpf] = {"nome": nome, "email": email, "livros_emprestados": []}
    return f"Usuário {nome} cadastrado com sucesso!"

def buscar_usuario(cpf):
    """Busca um usuário por CPF"""
    if cpf in usuarios:
        return usuarios[cpf]
    return None

# Módulo principal
if __name__ == "__main__":
    print(adicionar_livro("Python para Iniciantes", "João Silva", "123456789"))
    print(adicionar_usuario("Maria Santos", "maria@email.com", "987654321"))
    print(emprestar_livro("123456789", "Maria Santos"))

Explicação linha por linha:

  • Linha 1: # sistema_biblioteca.py - Comentário indicando nome do arquivo
  • Linha 2: # Este é um sistema modular completo com múltiplos módulos - Comentário explicativo
  • Linha 4: # Módulo: livros.py - Comentário indicando módulo de livros
  • Linha 5: livros = {} - Cria dicionário para armazenar livros
  • Linha 7: def adicionar_livro(titulo, autor, isbn): - Define função para adicionar livro
  • Linha 8: """Adiciona um novo livro ao sistema""" - Docstring da função
  • Linha 9: livros[isbn] = {"titulo": titulo, "autor": autor, "disponivel": True} - Adiciona livro com informações
  • Linha 10: return f"Livro '{titulo}' adicionado com sucesso!" - Retorna mensagem de confirmação
  • Linha 12: def buscar_livro(isbn): - Define função para buscar livro
  • Linha 13: """Busca um livro por ISBN""" - Docstring da função
  • Linha 14: if isbn in livros: - Verifica se livro existe
  • Linha 15: return livros[isbn] - Retorna informações do livro
  • Linha 16: return None - Retorna None se livro não encontrado

22. Criptografia

# crypto.py

def cifra_cesar(texto, chave):
    """Criptografa texto usando cifra de César"""
    resultado = ""
    
    for caractere in texto:
        if caractere.isalpha():
            # Determina se é maiúscula ou minúscula
            if caractere.isupper():
                # Criptografa maiúscula
                resultado += chr((ord(caractere) - ord('A') + chave) % 26 + ord('A'))
            else:
                # Criptografa minúscula
                resultado += chr((ord(caractere) - ord('a') + chave) % 26 + ord('a'))
        else:
            # Mantém caracteres não alfabéticos
            resultado += caractere
    
    return resultado

def descriptografar_cifra_cesar(texto_criptografado, chave):
    """Descriptografa texto usando cifra de César"""
    return cifra_cesar(texto_criptografado, -chave)

if __name__ == "__main__":
    texto_original = "Python"
    chave = 3
    
    texto_criptografado = cifra_cesar(texto_original, chave)
    texto_descriptografado = descriptografar_cifra_cesar(texto_criptografado, chave)
    
    print(f"Texto original: {texto_original}")
    print(f"Texto criptografado: {texto_criptografado}")
    print(f"Texto descriptografado: {texto_descriptografado}")

Explicação linha por linha:

  • Linha 1: # crypto.py - Comentário indicando nome do arquivo
  • Linha 3: def cifra_cesar(texto, chave): - Define função para criptografar
  • Linha 4: """Criptografa texto usando cifra de César""" - Docstring da função
  • Linha 5: resultado = "" - Inicializa string vazia para resultado
  • Linha 7: for caractere in texto: - Percorre cada caractere do texto
  • Linha 8: if caractere.isalpha(): - Verifica se caractere é alfabético
  • Linha 9: # Determina se é maiúscula ou minúscula - Comentário explicativo
  • Linha 10: if caractere.isupper(): - Verifica se é maiúscula
  • Linha 11: # Criptografa maiúscula - Comentário explicativo
  • Linha 12: resultado += chr((ord(caractere) - ord('A') + chave) % 26 + ord('A')) - Aplica cifra de César para maiúscula
  • Linha 13: else: - Se não for maiúscula
  • Linha 14: # Criptografa minúscula - Comentário explicativo
  • Linha 15: resultado += chr((ord(caractere) - ord('a') + chave) % 26 + ord('a')) - Aplica cifra de César para minúscula

23. Simulador de Dados

# simulador_dados.py
import random
from collections import Counter

def simular_dados(num_faces, num_lancamentos):
    """Simula lançamentos de dados e retorna frequência"""
    resultados = []
    
    for _ in range(num_lancamentos):
        resultado = random.randint(1, num_faces)
        resultados.append(resultado)
    
    # Conta frequência de cada face
    frequencia = Counter(resultados)
    
    return frequencia, resultados

def analisar_probabilidade(frequencia, num_lancamentos):
    """Analisa probabilidade de cada face"""
    probabilidades = {}
    
    for face, count in frequencia.items():
        probabilidades[face] = count / num_lancamentos
    
    return probabilidades

if __name__ == "__main__":
    # Simular 100 lançamentos de dado de 6 faces
    frequencia, resultados = simular_dados(6, 100)
    probabilidades = analisar_probabilidade(frequencia, 100)
    
    print("Frequência dos lançamentos:")
    for face, count in sorted(frequencia.items()):
        print(f"Face {face}: {count} vezes")
    
    print("\nProbabilidades:")
    for face, prob in sorted(probabilidades.items()):
        print(f"Face {face}: {prob:.2%}")

Explicação linha por linha:

  • Linha 1: # simulador_dados.py - Comentário indicando nome do arquivo
  • Linha 2: import random - Importa módulo random para gerar números aleatórios
  • Linha 3: from collections import Counter - Importa Counter para contar frequências
  • Linha 5: def simular_dados(num_faces, num_lancamentos): - Define função para simular dados
  • Linha 6: """Simula lançamentos de dados e retorna frequência""" - Docstring da função
  • Linha 7: resultados = [] - Inicializa lista para armazenar resultados
  • Linha 9: for _ in range(num_lancamentos): - Loop para cada lançamento
  • Linha 10: resultado = random.randint(1, num_faces) - Gera resultado aleatório
  • Linha 11: resultados.append(resultado) - Adiciona resultado à lista
  • Linha 13: # Conta frequência de cada face - Comentário explicativo
  • Linha 14: frequencia = Counter(resultados) - Conta frequência de cada resultado
  • Linha 16: return frequencia, resultados - Retorna frequência e lista de resultados

24. Analisador de Texto

# analisador_texto.py
import re
from collections import Counter

def analisar_texto(texto):
    """Analisa texto e retorna estatísticas"""
    # Remove pontuação e converte para minúsculas
    texto_limpo = re.sub(r'[^\w\s]', '', texto.lower())
    
    # Divide em palavras
    palavras = texto_limpo.split()
    
    # Calcula estatísticas
    num_palavras = len(palavras)
    num_caracteres = len(texto)
    num_caracteres_sem_espaco = len(texto.replace(' ', ''))
    
    # Conta frequência de palavras
    frequencia_palavras = Counter(palavras)
    palavra_mais_comum = frequencia_palavras.most_common(1)[0][0] if palavras else "Nenhuma"
    
    # Calcula tamanho médio das palavras
    tamanho_medio = sum(len(palavra) for palavra in palavras) / num_palavras if palavras else 0
    
    return {
        "palavras": num_palavras,
        "caracteres": num_caracteres,
        "caracteres_sem_espaco": num_caracteres_sem_espaco,
        "palavra_mais_comum": palavra_mais_comum,
        "tamanho_medio_palavra": round(tamanho_medio, 2),
        "frequencia_palavras": dict(frequencia_palavras.most_common(5))
    }

if __name__ == "__main__":
    texto = "Python é uma linguagem de programação incrível. Python é fácil de aprender."
    stats = analisar_texto(texto)
    
    print(f"Palavras: {stats['palavras']}")
    print(f"Caracteres: {stats['caracteres']}")
    print(f"Palavra mais comum: {stats['palavra_mais_comum']}")
    print(f"Tamanho médio das palavras: {stats['tamanho_medio_palavra']}")

Explicação linha por linha:

  • Linha 1: # analisador_texto.py - Comentário indicando nome do arquivo
  • Linha 2: import re - Importa módulo re para expressões regulares
  • Linha 3: from collections import Counter - Importa Counter para contar frequências
  • Linha 5: def analisar_texto(texto): - Define função para analisar texto
  • Linha 6: """Analisa texto e retorna estatísticas""" - Docstring da função
  • Linha 7: # Remove pontuação e converte para minúsculas - Comentário explicativo
  • Linha 8: texto_limpo = re.sub(r'[^\w\s]', '', texto.lower()) - Remove pontuação usando regex
  • Linha 10: # Divide em palavras - Comentário explicativo
  • Linha 11: palavras = texto_limpo.split() - Divide texto em lista de palavras
  • Linha 13: # Calcula estatísticas - Comentário explicativo
  • Linha 14: num_palavras = len(palavras) - Conta número de palavras
  • Linha 15: num_caracteres = len(texto) - Conta número de caracteres
  • Linha 16: num_caracteres_sem_espaco = len(texto.replace(' ', '')) - Conta caracteres sem espaços

25. Gerenciador de Projetos

# gerenciador_projetos.py
from pathlib import Path
import os

def criar_projeto(nome_projeto, tipo="python"):
    """Cria estrutura de projeto com template padrão"""
    base_path = Path(nome_projeto)
    
    # Cria estrutura de diretórios
    diretorios = [
        "src",
        "tests",
        "docs",
        "data",
        "scripts"
    ]
    
    for diretorio in diretorios:
        (base_path / diretorio).mkdir(parents=True, exist_ok=True)
    
    # Cria arquivos de template
    if tipo == "python":
        criar_arquivos_python(base_path, nome_projeto)
    elif tipo == "web":
        criar_arquivos_web(base_path, nome_projeto)
    
    return f"Projeto '{nome_projeto}' criado com estrutura padrão!"

def criar_arquivos_python(base_path, nome_projeto):
    """Cria arquivos de template para projeto Python"""
    # README.md
    readme_content = f"""# {nome_projeto}

    ## Descrição
    Projeto Python criado automaticamente.
    
    ## Instalação
    ```bash
    pip install -r requirements.txt
    ```
    
    ## Uso
    ```bash
    python src/main.py
    ```
    
    ## Testes
    ```bash
    python -m pytest tests/
    ```
    """
        
    (base_path / "README.md").write_text(readme_content)
    
    # requirements.txt
    (base_path / "requirements.txt").write_text("# Dependências do projeto\n")
    
    # main.py
    main_content = f"""#!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    \"\"\"
    {nome_projeto}
    Autor: Seu Nome
    Data: {os.popen('date').read().strip()}
    \"\"\"
    
    def main():
        print("Hello, World!")
        print("Projeto {nome_projeto} executado com sucesso!")
    
    if __name__ == "__main__":
        main()
    """
        
        (base_path / "src" / "main.py").write_text(main_content)

def criar_arquivos_web(base_path, nome_projeto):
    """Cria arquivos de template para projeto web"""
    # index.html
    html_content = f"""<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{nome_projeto}</title>
</head>
<body>
    <h1>Bem-vindo ao {nome_projeto}!</h1>
    <p>Projeto web criado automaticamente.</p>
</body>
</html>
"""
    
    (base_path / "index.html").write_text(html_content)

if __name__ == "__main__":
    print(criar_projeto("meu_app", "python"))
    print(criar_projeto("meu_site", "web"))

Explicação linha por linha:

  • Linha 1: # gerenciador_projetos.py - Comentário indicando nome do arquivo
  • Linha 2: from pathlib import Path - Importa classe Path do módulo pathlib
  • Linha 3: import os - Importa módulo os para operações do sistema
  • Linha 5: def criar_projeto(nome_projeto, tipo="python"): - Define função para criar projeto
  • Linha 6: """Cria estrutura de projeto com template padrão""" - Docstring da função
  • Linha 7: base_path = Path(nome_projeto) - Cria objeto Path com nome do projeto
  • Linha 9: # Cria estrutura de diretórios - Comentário explicativo
  • Linhas 10-16: Define lista com diretórios padrão do projeto
  • Linha 18: for diretorio in diretorios: - Percorre lista de diretórios
  • Linha 19: (base_path / diretorio).mkdir(parents=True, exist_ok=True) - Cria cada diretório
  • Linha 21: # Cria arquivos de template - Comentário explicativo
  • Linha 22: if tipo == "python": - Verifica tipo de projeto
  • Linha 23: criar_arquivos_python(base_path, nome_projeto) - Chama função para criar arquivos Python

Solução: Uso da biblioteca random

import random

numero_sorteado = random.randint(1, 100)
print(f"Número sorteado: {numero_sorteado}")

Conceitos-chave: Biblioteca random, função randint

Solução: Importação e uso de módulo

# teste_cumprimentos.py
import cumprimentos

mensagem = cumprimentos.dizer_oi()
print(mensagem)

Conceitos-chave: Importação de módulos, uso de funções externas

Solução: Módulo básico com funções simples

# cumprimentos.py
def dizer_oi():
    return "Olá!"

def dizer_tchau():
    return "Tchau!"

if __name__ == "__main__":
    print(dizer_oi())

Conceitos-chave: Definição de funções, if __name__ == "__main__"

11.13 Soluções dos Exercícios

11.13.1 Nível 1: Muito Fácil

Solução 1: Módulo cumprimentos.py

# cumprimentos.py
def dizer_oi():
    return "Olá!"

def dizer_tchau():
    return "Tchau!"

if __name__ == "__main__":
    print(dizer_oi())

Solução 2: Arquivo teste_cumprimentos.py

# teste_cumprimentos.py
import cumprimentos

mensagem = cumprimentos.dizer_oi()
print(mensagem)

Solução 3: Número aleatório

import random

numero_sorteado = random.randint(1, 100)
print(f"Número sorteado: {numero_sorteado}")

Solução 4: Data atual

import datetime

agora = datetime.datetime.now()
data_brasileira = agora.strftime('%d/%m/%Y')
print(f"Data atual: {data_brasileira}")

Solução 5: Raiz quadrada

import math

raiz = math.sqrt(144)
print(f"Raiz quadrada de 144: {raiz}")

11.13.2 Nível 2: Fácil

Solução 6: Módulo calculadora_avancada.py

# calculadora_avancada.py
import math

def area_circulo(raio):
    """Calcula a área de um círculo"""
    return math.pi * raio ** 2

def area_retangulo(largura, altura):
    """Calcula a área de um retângulo"""
    return largura * altura

def area_triangulo(base, altura):
    """Calcula a área de um triângulo"""
    return (base * altura) / 2

if __name__ == "__main__":
    print(f"Área do círculo (raio=5): {area_circulo(5):.2f}")
    print(f"Área do retângulo (4x6): {area_retangulo(4, 6)}")
    print(f"Área do triângulo (base=8, altura=3): {area_triangulo(8, 3)}")

Solução 7: Módulo validadores.py

# validadores.py

def validar_email(email):
    """Validação básica de email"""
    return '@' in email and '.' in email.split('@')[1]

def validar_cpf(cpf):
    """Validação básica de CPF (apenas formato)"""
    cpf_limpo = cpf.replace('.', '').replace('-', '')
    return len(cpf_limpo) == 11 and cpf_limpo.isdigit()

def validar_telefone(telefone):
    """Validação básica de telefone"""
    telefone_limpo = telefone.replace('(', '').replace(')', '').replace('-', '').replace(' ', '')
    return len(telefone_limpo) >= 10 and telefone_limpo.isdigit()

if __name__ == "__main__":
    print(f"Email válido: {validar_email('teste@email.com')}")
    print(f"CPF válido: {validar_cpf('123.456.789-00')}")
    print(f"Telefone válido: {validar_telefone('(11) 99999-9999')}")

Solução 8: Sorteio de brindes

import random

brindes = ["Caneta", "Caderno", "Camiseta", "Livro", "Mousepad"]
brinde_sorteado = random.choice(brindes)
print(f"Brinde sorteado: {brinde_sorteado}")

Solução 9: Dias para aniversário

import datetime

# Substitua pela sua data de nascimento
nascimento = datetime.date(1990, 5, 15)
hoje = datetime.date.today()

# Calcular próximo aniversário
proximo_aniversario = datetime.date(hoje.year, nascimento.month, nascimento.day)

if proximo_aniversario < hoje:
    proximo_aniversario = datetime.date(hoje.year + 1, nascimento.month, nascimento.day)

dias_restantes = (proximo_aniversario - hoje).days
print(f"Dias para o próximo aniversário: {dias_restantes}")

Solução 10: Listar arquivos .txt

import os

arquivos = os.listdir('.')
arquivos_txt = [arquivo for arquivo in arquivos if arquivo.endswith('.txt')]
print(f"Arquivos .txt encontrados: {arquivos_txt}")

💡 Dica: Continue praticando com os exercícios dos níveis mais altos! Cada solução te ensina algo novo sobre módulos e bibliotecas.

11.14 Próximos Passos: Continue Aprendendo!

Parabéns! Você agora domina os conceitos fundamentais de módulos e bibliotecas em Python! 🎉

11.14.1 O que você aprendeu:

  • Conceito de módulos: Como organizar código em arquivos separados
  • Diferentes formas de importar: import, from ... import, import ... as
  • Variável __name__: Como controlar quando código executa
  • Bibliotecas built-in: datetime, random, math, os, pathlib
  • Instalação de bibliotecas: Como usar pip install
  • Organização de projetos: Estrutura modular e reutilizável

11.14.2 Desafios para Continuar:

  1. Crie seu próprio pacote: Organize vários módulos em uma pasta com __init__.py
  2. Explore bibliotecas externas: Instale e teste requests, beautifulsoup4, flask
  3. Contribua com código aberto: Encontre projetos no GitHub e contribua com módulos
  4. Documente seus módulos: Use docstrings e crie documentação clara

11.14.3 Próximo Capítulo:

No Capítulo 12, vamos aprender sobre APIs - Parte 1 (Consumindo APIs)! Você vai descobrir como:

  • Fazer requisições HTTP para APIs externas
  • Trabalhar com dados JSON
  • Usar APIs públicas como ViaCEP e OpenWeatherMap
  • Criar aplicações que consomem dados da internet

🎯 batel.tech: Quer praticar mais? Acesse batel.tech e encontre projetos práticos para aplicar seus conhecimentos de módulos e bibliotecas! Lá você pode colaborar com outros desenvolvedores e construir projetos incríveis usando Python!


11.15 Referências Bibliográficas


Capítulo 11 concluído! 🎉 Agora você está pronto para criar código modular e profissional. No próximo capítulo, vamos conectar seu Python com o mundo através de APIs!