Recursão e Busca Binária
1. Recursão
Uma função recursiva é aquela que chama a si mesma durante sua execução. Este mecanismo é útil para resolver problemas que podem ser divididos em subproblemas semelhantes.
# Chamada recursiva direta
def mostrar_mensagem():
print('Olá do mundo recursivo')
mostrar_mensagem() # Chamada a si mesma
# Chamada recursiva indireta
def operacao_a():
print('Operação A chamada')
operacao_b()
def operacao_b():
print('Operação B chamada')
# Para evitar loop infinito, deve-se ter uma condição de parada clara.
# A eficiência da recursão em Python é limitada; outras linguagens possuem otimizações como recursão de cauda.
Características e Cuidados com a Recursão:
1. É obrigatório ter uma condição de parada bem definida.
2. A cada chamada recursiva, o tamanho do problema deve diminuir.
3. Recursão profunda pode causar estouro de pilha (stack overflow), pois cada chamada adiciona um quadro à pilha.
# Python define um limite de profundidade recursiva. É possível verificar e ajustar este limite:
import sys
print(sys.getrecursionlimit()) # Profundidade padrão, ex: 1000
sys.setrecursionlimit(500) # Altera a profundidade máxima
2. Busca Binária
A busca binária é um algoritmo eficeinte para localizar um elemento em uma lista ordenada, dividindo repetidamente o intervalo de busca pela metade.
lista_ordenada = [2, 5, 8, 12, 16, 23, 38, 45, 67, 89]
alvo = 23
def busca_binaria(dados, valor):
if len(dados) == 0:
return False
meio = len(dados) // 2
if dados[meio] == valor:
return True
elif valor < dados[meio]:
return busca_binaria(dados[:meio], valor)
else:
return busca_binaria(dados[meio+1:], valor)
encontrado = busca_binaria(lista_ordenada, alvo)
print(f"Elemento {alvo} encontrado: {encontrado}")
Funções Anônimas (Lambda)
Funções aônimas, ou lambdas, são pequenas funções definidas sem um nome. Elas são frequentemente usadas para operações curtas e pontuais.
# Função anônima simples
dobrar = lambda x: x * 2
print(dobrar(5)) # Saída: 10
# Aplicações comuns com funções integradas:
pontuacoes = {'Ana': 85, 'Carlos': 92, 'Beatriz': 78, 'Daniel': 95}
# Encontrar a chave com o maior valor
melhor_aluno = max(pontuacoes, key=lambda chave: pontuacoes[chave])
print(f"Melhor aluno: {melhor_aluno}")
# Ordenar dicionário por valores
ordenado_por_nota = sorted(pontuacoes.items(), key=lambda item: item[1], reverse=True)
print("Ranking:", ordenado_por_nota)
# Transformar elementos de uma lista
frutas = ['maçã', 'banana', 'cereja']
frutas_com_preco = list(map(lambda fruta: f"{fruta}: R${len(fruta)*1.5:.2f}", frutas))
print(frutas_com_preco)
# Reduzir uma sequência a um único valor
from functools import reduce
numeros = [10, 20, 30, 40]
soma_total = reduce(lambda acumulador, x: acumulador + x, numeros, 0)
print(f"Soma total: {soma_total}")
# Filtrar elementos
notas = [65, 90, 45, 78, 88, 32, 95]
aprovados = list(filter(lambda nota: nota >= 70, notas))
print("Aprovados:", aprovados)
Funções Integradas (Built-in) do Python
Python possui um conjunto de funções integradas disponíveis globalmente, sem necessidade de importação.
# Funções matemáticas e de conversão:
print(abs(-15)) # Valor absoluto: 15
print(round(3.14159, 2)) # Arredondamento: 3.14
print(pow(2, 10)) # Potência: 1024
print(divmod(17, 5)) # Quociente e resto: (3, 2)
# Conversão de tipos:
texto_numero = "123"
numero = int(texto_numero)
print(type(numero))
# Operações em sequências:
lista = [5, 2, 8, 1, 9]
print(f"Máximo: {max(lista)}, Mínimo: {min(lista)}, Soma: {sum(lista)}")
# Verificação de tipos e booleanos:
print(isinstance(10, int)) # True
print(bool(0)) # False
print(all([True, 1, 'ok'])) # True
print(any([None, 0, '', []])) # False
# Manipulação de nomes e atributos:
class Exemplo:
atributo = 42
obj = Exemplo()
print(hasattr(obj, 'atributo')) # True
setattr(obj, 'novo_atributo', 100)
print(getattr(obj, 'novo_atributo')) # 100
Módulos e Pacotes
1. Módulos
Um módulo é um arquivo Python (extensão .py) que contém definições e instruções. A modularização ajuda a organizar o código e reutilizar funcionalidades.
# Conteúdo do arquivo 'calculadora.py'
def adicionar(a, b):
return a + b
def subtrair(a, b):
return a - b
# Utilizando o módulo em outro arquivo:
import calculadora
resultado = calculadora.adicionar(10, 5)
print(f"Resultado da adição: {resultado}")
# Importação seletiva com apelido:
from calculadora import adicionar as soma
print(f"Soma: {soma(7, 3)}")
# Importação de todos os nomes (usar com cautela):
from calculadora import *
2. Pacotes
Um pacote é um diretório que contém um arquivo especial __init__.py (opcional no Python 3, mas recomendado) e outros módulos ou subpacotes. Ele permite uma estrutura hierárquica.
# Estrutura de exemplo:
# meu_projeto/
# ├── __init__.py
# ├── modulo1.py
# └── subpacote/
# ├── __init__.py
# └── modulo2.py
# Dentro de modulo2.py:
def func_util():
return "Função do subpacote"
# Para importar:
# importação absoluta
from meu_projeto.subpacote.modulo2 import func_util
# importação relativa (dentro do mesmo pacote)
# No arquivo modulo1.py, dentro de meu_projeto:
# from .subpacote.modulo2 import func_util
3. Caminhos de Busca
O Python procura módulos em: 1) Diretório atual, 2) Variável de ambiente PYTHONPATH, 3) Diretórios padrão de instalação.
import sys
# Visualizar e modificar o caminho de busca
print(sys.path)
sys.path.insert(0, '/caminho/para/meus/modulos')
Padrões de Desenvolvimento
Adotar uma estrutura de diretórios consistente melhora a manutenibilidade e colaboração em projetos.
# Estrutura de projeto típica:
meu_projeto/
│
├── bin/ # Scripts executáveis
│ └── iniciar.py
│
├── core/ # Lógica principal do aplicativo
│ ├── __init__.py
│ └── processos.py
│
├── conf/ # Arquivos de configuração
│ ├── settings.py
│ └── logging.ini
│
├── lib/ # Bibliotecas e utilitários auxiliares
│ ├── __init__.py
│ └── funcoes_aux.py
│
├── testes/ # Testes automatizados
│ └── test_processos.py
│
├── docs/ # Documentação
│ └── readme.md
│
└── db/ # Dados persistentes (se aplicável)
# Exemplo simplificado de inicialização (bin/iniciar.py):
import sys
import os
# Adiciona a raiz do projeto ao caminho
raiz_projeto = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, raiz_projeto)
from core.processos import main as executar_app
from conf import settings
if __name__ == '__main__':
print(f"Iniciando com configuração: {settings.AMBIENTE}")
executar_app()
Esta abordagem organiza o código em responsabilidades claras, facilitando testes, configuração e distribuição.