Compreensões de listas em Python oferecem uma sintaxe concisa para criar listas. Por exemplo, para gerar uma lista de números de 0 a 9:
lista_base = [elemento for elemento in range(10)]
Filtrar elementos é possível adicionando condições. Para obter apenas números pares:
numeros_pares = [num for num in range(10) if num % 2 == 0]
Compreensões aninhadas podem criar estruturas complexas, como pares ordenados:
pares = [(x, y) for x in range(5) for y in range(4)]
Para achatar uma lista de listas:
lista_aninhada = [[1, 2], [3, 4]]
achatar = [item for sublist in lista_aninhada for item in sublist]
Compreensões de dicionários seguem um princípio similar, gerando pares chave-valor. Exemplo com seleção aleatória:
import random
valores_originais = [0, 2, 6, 12, 84, 65, 21, 86, 26, 49]
dicionario_aleatorio = {chave: random.choice(valores_originais) for chave in range(10)}
Inverter chaves e valores em um dicionário existente:
dicionario_original = {'a': 1, 'b': 2, 'c': 3}
dicionario_invertido = {valor: chave for chave, valor in dicionario_original.items()}
Compreensões de conjuntos eliminam duplicatas automaticamente:
conjunto_numeros = {num for num in range(10)}
Geradores são objetos que produzem valores sob demanda, economizando memória. Podem ser criados com sintaxe similar às compreensões, mas com parênteses:
gerador_par = (n for n in range(50) if n % 2 == 0)
print(next(gerador_par)) # Obtém o primeiro valor
print(next(gerador_par)) # Obtém o segundo valor
Funções geradoras usam a palavra-chave yield para pausar e retomar a execução. Exemplo de uma contagem:
def contador_limite(limite):
atual = 0
while atual < limite:
yield atual
atual += 1
gen = contador_limite(5)
for valor in gen:
print(valor)
O yield permite comunicação bidirecional com o gerador. Ao enviar valores, use send():
def gerador_interativo():
recebido = yield "Início"
while recebido is not None:
recebido = yield f"Recebi: {recebido}"
gen = gerador_interativo()
print(next(gen)) # Inicializa o gerador
print(gen.send("Dados")) # Envia um valor
Sequências como Fibonacci podem ser implementadas eficientemente com geradores:
def fibonacci(quantidade):
a, b = 0, 1
for _ in range(quantidade):
yield a
a, b = b, a + b
seq_fib = fibonacci(10)
print(list(seq_fib))
Iteradores são objetos que suportam iteração via next(). Todo gerador é um iterador, mas nem todo iterador é um gerador. Objetos iteráveis, como listas, podem ser convertidos em iteradores:
lista_iteravel = [1, 2, 3, 4]
iterador_lista = iter(lista_iteravel)
print(next(iterador_lista)) # 1
print(next(iterador_lista)) # 2
Vantagens dos iteradores incluem processamento preguiçoso e capacidade de lidar com dados sem índices. Desvantagens: não possuem comprimento definido e não permitem acesso reverso.
Decoradores em Python estendem o comportamento de funções sem modificá-las diretamente. Eles se baseiam em funções de alta ordem e closures. Uma closure ocorre quando uma função interna referencia variáveis de seu escopo externo.
def verificar_autenticacao(func):
def wrapper(*args, **kwargs):
print("Autenticação em andamento")
return func(*args, **kwargs)
return wrapper
@verificar_autenticacao
def acessar_recurso(dado):
print(f"Acessando: {dado}")
acessar_recurso("documento_confidencial")
Decoradores podem aceitar argumentos adicoinais, exigindo uma camada extra de funções:
def decorador_com_parametro(param):
def decorador(func):
def wrapper(*args, **kwargs):
if param == "ativo":
print("Modo ativo")
else:
print("Modo inativo")
return func(*args, **kwargs)
return wrapper
return decorador
@decorador_com_parametro("ativo")
def calcular(a, b):
return a + b
@decorador_com_parametro("inativo")
def multiplicar(a, b):
return a * b
print(calcular(3, 4))
print(multiplicar(3, 4))
Esta abordagem permite reutilizar lógica de autenticação, logging ou validação de maneira modular.