Exercícios de Python - Do Básico ao Avançado

Fundamentos de Loops e Estruturas de Repetição

Tabela de Multiplicação

Para imprimir a tabela de multiplicação de 1 a 9, utilizamos loops aninhados:

for i in range(1, 10):
    for j in range(1, i + 1):
        print("{}*{}={}".format(j, i, j * i), end=" ")
    print()

Construção de Pirâmides

A construção de pirâmides com asteriscos requer análise matemática. Para uma pirâmide de 5 níveis:

# Fórmula: espaços = nível_máximo - nível_atual
# Fórmula: asteriscos = 2 * nível_atual - 1

nivel = 5
for i in range(1, nivel + 1):
    espacos = nivel - i
    asteriscos = 2 * i - 1
    print(" " * espacos + "*" * asteriscos)

Manipulação de Estruturas de Dados

Fila e Pilha

  • Fila (FIFO): append() para adicionar, pop(0) para remover
  • Pilha (LIFO): append() para adicionar, pop() para remover

Tuplas e Dicionários

Tuplas são listas imutáveis - a referência de memória não pode mudar, mas podem conter objetos mutáveis como listas:

t = (1, 2, ['A'])
t[2].append('B')  # Válido - modifica a lista interna

Para buscar valores em dicionários com segurança:

valor = d.get('chave', None)

Iteradores e Geradores

Iterable vs Iterador

Objetos iteráveis implementam __iter__(), enquanto iteradores implementam tanto __iter__() quanto __next__(). A diferença principal está no estado - iteradores mantêm posição atual:

from collections.abc import Iterable, Iterator

def verificar_tipo(obj):
    print(f"{obj} é iterable: {isinstance(obj, Iterable)}")
    print(f"{obj} é iterador: {isinstance(obj, Iterator)}")

Geradores

Geradores são iteradores especiais criados com a palavra-chave yield:

def gerador_numeros():
    for i in range(5):
        yield i

gen = gerador_numeros()
print(next(gen))  # 0
print(next(gen))  # 1

Com yield, a função pausa automaticamente e mantém o estado entre chamadas, ideal para processar grandes volumes de dados sem ocupar memória.

Operações com Arquivos

Copia de Arquivos

def copiar_arquivo(origem, destino):
    with open(origem, 'r') as src, open(destino, 'w') as dst:
        for linha in src:
            dst.write(linha)

Monitoramento de Arquivos (tail -f)

import time

def monitorar_log(arquivo):
    with open(arquivo, 'rb') as f:
        f.seek(0, 2)  # Ir para o final
        while True:
            linha = f.readline()
            if linha:
                print(linha.decode('utf-8'), end='')
            else:
                time.sleep(0.3)

Funções e Escopo de Variáveis

Exercícios com Funções

# Contador usando closure
def criar_contador():
    contador = 0
    def incremento():
        nonlocal contador
        contador += 1
        return contador
    return incremento

contador = criar_contador()
print(contador())  # 1
print(contador())  # 2

Análise de Escopo

Exemplo de resolução de nomes em Python:

x = 111

def func():
    print(x)  # Busca x no escopo global

func()  # Output: 111

x = 111

def func():
    print(x)  # ReferenceError - variável local não inicializada
    x = 222

func()

Decoardores

Decorador Simples

import time

def medidor_tempo(func):
    def wrapper(*args, **kwargs):
        inicio = time.time()
        resultado = func(*args, **kwargs)
        print(f"Tempo: {time.time() - inicio}")
        return resultado
    return wrapper

@medidor_tempo
def processo_lento():
    time.sleep(1)
    return "Concluído"

Decorador com Autenticação

def autenticar(func):
    def wrapper(*args, **kwargs):
        if not verificar_login():
            return redirect('/login')
        return func(*args, **kwargs)
    return wrapper

Decorador com Parâmetros

def verificar_permissao(permissao_requerida):
    def decorador(func):
        def wrapper(*args, **kwargs):
            if usuario_tem_permissao(permissao_requerida):
                return func(*args, **kwargs)
            raise PermissaoNegada()
        return wrapper
    return decorador

Processamento de Dados com Funções Built-in

Leitura e Processamneto de Arquivos CSV

Dado um arquivo com formato: nome gênero idade salário

egon male 18 3000
alex male 38 30000
wupeiqi female 28 20000

Converter para lista de dicionários:

with open('dados.txt') as arquivo:
    linhas = arquivo.readlines()
    
cabecalhos = ['nome', 'genero', 'idade', 'salario']
pessoas = []
for linha in linhas:
    valores = linha.strip().split()
    pessoa = dict(zip(cabecalhos, valores))
    pessoa['idade'] = int(pessoa['idade'])
    pessoa['salario'] = int(pessoa['salario'])
    pessoas.append(pessoa)

Funções de Aggregação

# Soma total de salários
total = sum(p['salario'] for p in pessoas)

# Maior salário
maior = max(pessoas, key=lambda p: p['salario'])

# Filtrar homens
ns_homens = [p['nome'] for p in pessoas if p['genero'] == 'male']

# Nomes em maiúsculo
nomes_upper = [p['nome'].upper() for p in pessoas]

# Filtrar nomes que não começam com 'a'
filtrados = [p for p in pessoas if not p['nome'].startswith('a')]

Lambda com max

# Encontrar pessoa mais jovem
mais_jovem = min(pessoas, key=lambda p: p['idade'])

# Encontrar pessoa mais velha
mais_velho = max(pessoas, key=lambda p: p['idade'])

Sistema ATM - Aplicação Completa

Implementar um sistema de ATM com as seguintes operações:

  1. Registro: Criar nova conta com saldo inicial
  2. Login: Autenticar usuário com bloqueio após 3 tentativas
  3. Depósito: Adicionar fundos à conta
  4. Transferência: Enviar dinheiro entre contas
  5. Saque: Remover fundos da conta
  6. Consulta: Verificar saldo atual

Dados armazenados em arquivo texto no formato: usuário:senha:saldo:status

Recursão

Sequência de Fibonacci

def fibonacci(n, a=0, b=1):
    if n == 0:
        return
    print(a, end=' ')
    fibonacci(n-1, b, a+b)

fibonacci(10)  # 0 1 1 2 3 5 8 13 21 34

Achatamento de Lista Aninhada

def achatar(lista):
    resultado = []
    for elemento in lista:
        if isinstance(elemento, list):
            resultado.extend(achatar(elemento))
        else:
            resultado.append(elemento)
    return resultado

numeros = [1, 2, [3, [4, 5, [6, 7]]]]
print(achatar(numeros))  # [1, 2, 3, 4, 5, 6, 7]

Módulos e Importação

Princípios fundamentais:

  • Separar código em módulos lógicos
  • Compartilhar apenas funções de uso comum
  • Nãopoluir o namespace global

Diferença entre executar e importar um módulo:

# Quando executado: __name__ == '__main__'
# Quando importado: __name__ == 'nome_modulo'

if __name__ == '__main__':
    main()

O namespace de um módulo importado permanece na memória enquanto o módulo que o importou estiver em execução.

Tags: Python funções decoradores iteradores geradores

Publicado em 6-27 05:44