Ter funções como cidadãos de primeira classe permite o que chamamos de Programação Funcional ou Programação Orientada a Aspectos, que são estilos de programação muito poderosos para criar código mais flexível, reutilizável e, muitas vezes, mais conciso e expressivo. Este conceito é a base para entender as funcionalidades avançadas. Significa que:
Podem ser atribuídas a variáveis: Você pode armazenar uma função em uma variável e usá-la como se fosse a função original.
def saudacao(nome):
return f"Olá, {nome}!"
minha_saudacao = saudacao
print(minha_saudacao("Mundo")) # Saída: Olá, Mundo!
Exemplo Real:
Imagine que você tem uma lógica complexa de cálculo de imposto. Em vez de chamar calcula_imposto_padrao()
, você pode ter uma variável estrategia_imposto
que aponta para calcula_imposto_padrao
ou calcula_imposto_vip
, dependendo do tipo de cliente.
def calcular_imposto_padrao(valor):
return valor * 0.10
def calcular_imposto_vip(valor):
return valor * 0.05
tipo_cliente = "VIP" # Isso poderia vir de um banco de dados ou input do usuário
if tipo_cliente == "VIP":
estrategia_imposto = calcular_imposto_vip
else:
estrategia_imposto = calcular_imposto_padrao
print(estrategia_imposto(1000)) # Chama a função que foi atribuída à variável
É uma forma de polimorfismo em tempo de execução sem usar classes, apenas funções.
Podem ser passadas como argumentos para outras funções: Isso permite criar funções mais genéricas que operam sobre outras funções. Funções que recebem outras funções como argumento (ou as retornam) são chamadas de Higher-Order Functions.Python
def executar_operacao(operacao, a, b):
return operacao(a, b)
def somar(x, y):
return x + y
def multiplicar(x, y):
return x * y
print(executar_operacao(somar, 5, 3)) # Saída: 8
print(executar_operacao(multiplicar, 5, 3)) # Saída: 15
Exemplo Real:
Imagine uma função que processa uma lista de dados. Você quer que essa função seja capaz de aplicar diferentes transformações aos dados (ex: dobrar, triplicar, elevar ao quadrado).
def processar_lista(lista, funcao_transformacao):
resultados = []
for item in lista:
resultados.append(funcao_transformacao(item))
return resultados
def dobrar(x):
return x * 2
def quadrado(x):
return x * x
numeros = [1, 2, 3, 4]
print(processar_lista(numeros, dobrar)) # Saída: [2, 4, 6, 8]
print(processar_lista(numeros, quadrado)) # Saída: [1, 4, 9, 16]
Isso é a essência do padrão Strategy (Estratégia) em programação.
Podem ser retornadas por outras funções: Uma função pode gerar e retornar uma nova função.
def criar_multiplicador(fator):
def multiplicador(numero):
return numero * fator
return multiplicador
dobrar = criar_multiplicador(2)
triplicar = criar_multiplicador(3)
print(dobrar(10)) # Saída: 20
print(triplicar(10)) # Saída: 30
Isso permite criar funções personalizadas ou "fábricas de funções". A função externa (closure) "lembra" o estado em que foi criada (fator
), mesmo depois que a função externa terminou de ser executada.
Exemplo Real:
Ideal para gerar funções com configurações pré-definidas ou para criar decoradores (que veremos a seguir). Imagine uma função que cria validadores de senha. Python
def criar_validador_senha(min_length):
def validar_senha(senha):
return len(senha) >= min_length
return validar_senha
validador_senha_8_caracteres = criar_validador_senha(8)
validador_senha_12_caracteres = criar_validador_senha(12)
print(validador_senha_8_caracteres("abcde")) # Saída: False
print(validador_senha_8_caracteres("abcdefgh")) # Saída: True
print(validador_senha_12_caracteres("abcdefgh")) # Saída: False
Isso permite gerar funções que já vêm "pré-configuradas" com algum valor, sem a necessidade de passar esse valor toda vez que a função for chamada.