Trilha de aprendizado · Nível 9 · Tutorial 1

Passar funções como argumentos

Ao concluir, você será capaz de receber funções como parâmetros para variar o comportamento de uma operação e personalizar a ordenação de listas.

  • Nível: Intermediário
  • Duração: 18 min
  • 6 passos
Passar funções como argumentos

Passo 1 de 6

Distinguir a função do resultado da chamada

Veja como um nome pode se referir à própria função — sem executá-la — e como os parênteses mudam essa ação.

Função também é um valor

O nome e a chamada são diferentes

Depois de definir uma função, seu nome representa a própria função. Portanto, ele pode ser atribuído a outro nome, assim como um número ou uma string.

Em mensagem = saudacao, não há parênteses: Python associa mensagem à função já criada. O corpo da função não é executado nesse momento.

Dois nomes, uma função

A atribuição cria outra referência para a mesma função.

Diagrama mostrando os nomes saudacao e mensagem apontando para um único objeto de função; uma chamada mensagem() aponta para o valor retornado.

Sem parênteses, os dois nomes apontam para a função. Com parênteses, ocorre uma chamada.

Parênteses executam a função

Atribuir e chamar

Execute este código e observe as duas saídas.

python
def saudacao():
    print("Executando o corpo")
    return "Olá!"

mensagem = saudacao
print(mensagem)
print(mensagem())

Leia o que acontece

mensagem = saudacao associa outro nome à função, sem imprimir nada.

print(mensagem) mostra uma representação do objeto função, parecida com <function saudacao at ...>; o endereço varia.

Já mensagem() chama a função: primeiro ela imprime Executando o corpo e depois produz o retorno "Olá!", que o print externo exibe.

Dica

Regra prática

Use o nome sem () quando quiser se referir à função. Use () quando quiser executá-la e obter seu retorno.

Classifique cada expressão

O que cada linha faz?

Considere que saudacao já é uma função. Relacione cada expressão à sua ação.

Toque em um item e depois no par correspondente.

Preveja a chamada pelo novo nome

Código para analisar

python
def dobrar(numero):
    return numero * 2

calcular = dobrar
resultado = calcular(7)
print(resultado)

Qual é a saída?

Considerando o código, o que será exibido?

Passo 2 de 6

Receber uma função para variar o comportamento

Use uma função recebida como parâmetro para variar uma operação sem reescrever sua estrutura.

Uma função que recebe outra

Função como parâmetro

Uma função pode receber outra função como argumento. Ela é chamada de função de alta ordem.

No exemplo, aplicar recebe operacao. Dentro de aplicar, o nome operacao passa a se referir à função que foi fornecida na chamada. Os parênteses em operacao(valor) são o que executam a função recebida.

Estrutura da receptora

python
def aplicar(operacao, valor):
    resultado = operacao(valor)
    return resultado

Fluxo de execução

Diagrama mostrando o valor 5 entrando na função aplicar, seguindo para uma função recebida e retornando como resultado para quem chamou aplicar.

A receptora escolhe quando chamar a função recebida, qual valor enviar e o que devolver.

Mesmo corpo, comportamentos diferentes

Passe a função, sem chamá-la

Ao chamar aplicar, passe o nome da função sem parênteses. Assim, dobrar ou formatar_preco é entregue como valor para operacao.

A mesma receptora funciona com as duas funções porque ela chama a função recebida usando o valor definido em seu próprio corpo.

Duas operações para a mesma receptora

python
def aplicar(operacao, valor):
    return operacao(valor)


def dobrar(numero):
    return numero * 2


def formatar_preco(numero):
    return f"R$ {numero:.2f}"

print(aplicar(dobrar, 8))
print(aplicar(formatar_preco, 8))

Exemplo

Resultados

aplicar(dobrar, 8) devolve 16.

aplicar(formatar_preco, 8) devolve 'R$ 8.00'.

O corpo de aplicar não mudou. O comportamento mudou porque a função fornecida mudou.

Pratique o encaminhamento

Complete a chamada

Complete o corpo para executar a função recebida com valor e devolver seu resultado:

def transformar(acao, valor):
    return ______

Preveja a variação

Qual será o resultado?

Considere:

def aplicar(operacao, valor):
    return operacao(valor)

def mensagem(nome):
    return f"Olá, {nome}!"

resultado = aplicar(mensagem, "Ana")

Qual é o valor de resultado?

Passo 3 de 6

Fornecer os argumentos que a função espera

Verifique se a função recebida aceita exatamente a chamada que a função receptora fará.

A chamada define o contrato

Compatibilidade na hora de chamar

Passar uma função como valor é apenas o primeiro passo. A função receptora também precisa chamá-la de uma forma que ela aceite.

Observe a expressão de chamada dentro da receptora: ela define quantos argumentos serão enviados e se eles serão posicionais ou nomeados. A função recebida precisa ser compatível com essa expressão.

O encaixe entre chamada e parâmetros

Compare a chamada feita por aplicar com os parâmetros de cada função possível.

Diagrama mostrando uma função receptora que chama uma função recebida com dois argumentos e comparando uma função com dois parâmetros compatíveis a uma função com apenas um parâmetro incompatível.

A compatibilidade depende da chamada que a receptora realmente executa.

Uma chamada com dois argumentos

A receptora sempre chama operacao com numero e percentual.

python
def aplicar(numero, percentual, operacao):
    return operacao(numero, percentual)


def aumentar(valor, percentual):
    return valor * (1 + percentual / 100)


resultado = aplicar(200, 10, aumentar)
print(resultado)  # 220.0

Quando os parâmetros não combinam

Função passada, chamada inválida

Nesta versão, aplicar continua enviando dois argumentos. Porém, dobrar aceita somente um parâmetro. O erro só acontece quando aplicar tenta executar operacao(numero, percentual).

Quantidade incompatível

python
def aplicar(numero, percentual, operacao):
    return operacao(numero, percentual)


def dobrar(valor):
    return valor * 2


resultado = aplicar(200, 10, dobrar)
# TypeError: dobrar() takes 1 positional argument but 2 were given

Atenção

Passar não é executar

aplicar(200, 10, dobrar) pode receber a função dobrar como valor. Isso não garante que dobrar aceite os argumentos usados depois pela receptora. Leia a chamada interna para encontrar a causa do TypeError.

Posicionais e nomeados também precisam encaixar

Os nomes enviados importam

Se a receptora usa argumentos nomeados, os nomes da chamada precisam corresponder aos parâmetros da função fornecida. Além disso, os valores necessários precisam estar disponíveis na receptora para serem encaminhados.

Encaminhando por nome

calcular_desconto usa os mesmos nomes escolhidos pela chamada interna.

python
def aplicar_desconto(preco, taxa, operacao):
    return operacao(valor=preco, percentual=taxa)


def calcular_desconto(valor, percentual):
    return valor * (1 - percentual / 100)


print(aplicar_desconto(80, 25, calcular_desconto))  # 60.0

Exemplo

Nome incompatível

Se a função fosse definida como def calcular_desconto(preco, percentual):, a chamada operacao(valor=preco, percentual=taxa) falharia: valor não é um nome de parâmetro aceito. Uma correção simples é mudar o parâmetro para valor ou chamar a operação com preco=preco.

Verifique a compatibilidade

Escolha uma função compatível

Considere:

def executar(mensagem, acao):
    return acao(mensagem)

Qual função pode ser passada como acao sem alterar executar?

Explique uma correção

Corrija sem mudar a receptora

Analise o código:

def usar(valor, funcao):
    return funcao(valor)


def adicionar(numero, incremento):
    return numero + incremento

Explique por que usar(10, adicionar) falha e descreva uma correção simples. Não use recursos de adaptação automática.

Escreva pelo menos 40 caracteres (0/40).

Passo 4 de 6

Escolher entre sorted e list.sort

Compare as duas formas de ordenar listas e escolha a que preserva ou altera a lista original conforme o requisito.

Duas operações, dois efeitos

Preservar ou alterar?

Python oferece duas formas comuns de ordenar uma lista. A escolha depende do que deve acontecer com a lista que você já tem:

  • sorted(lista) cria e devolve uma nova lista em ordem crescente. A lista original continua como estava.
  • lista.sort() reorganiza a própria lista em ordem crescente e devolve None.

Portanto, use sorted quando precisar manter a ordem original disponível. Use sort quando a própria lista deve passar a ficar ordenada.

Efeito sobre a lista

Observe que os mesmos valores levam a resultados diferentes quanto à lista original e ao retorno.

Diagrama comparando sorted e list.sort: uma lista inicial [8, 3, 5]; sorted gera uma nova lista [3, 5, 8] e preserva a inicial; list.sort transforma a lista inicial em [3, 5, 8] e retorna None.

sorted devolve outra lista; list.sort muda a lista usada na chamada e devolve None.

Veja o retorno e o estado

Chamadas independentes

Execute este código no seu editor para confirmar os valores impressos.

python
numeros = [8, 3, 5]
ordenados = sorted(numeros)

print(numeros)     # [8, 3, 5]
print(ordenados)   # [3, 5, 8]

outros_numeros = [8, 3, 5]
retorno = outros_numeros.sort()

print(outros_numeros)  # [3, 5, 8]
print(retorno)         # None

Exemplo

Armadilha comum

Não atribua o retorno de sort() esperando receber uma lista:

nomes = ["Bia", "Ana", "Caio"]
ordenados = nomes.sort()

print(ordenados)  # None
print(nomes)      # ['Ana', 'Bia', 'Caio']

A lista ordenada está em nomes, pois foi ela que sort() alterou.

Dica

Regra prática

Se precisar usar tanto a ordem de entrada quanto a ordem ordenada, escolha sorted. Se não precisar preservar a ordem anterior e quer atualizar a mesma lista, escolha sort.

Inverter a direção

Ordem decrescente

Por padrão, as duas operações ordenam em ordem crescente. Para inverter a direção, passe o argumento nomeado reverse=True.

Esse argumento não muda a diferença principal: sorted continua devolvendo uma nova lista, enquanto sort continua alterando a lista existente.

reverse=True nas duas operações

Compare o resultado e o estado das listas.

python
pontuacoes = [12, 30, 18]
ranking = sorted(pontuacoes, reverse=True)

print(pontuacoes)  # [12, 30, 18]
print(ranking)     # [30, 18, 12]

tentativas = [12, 30, 18]
tentativas.sort(reverse=True)

print(tentativas)  # [30, 18, 12]

Decida a operação

Preservar a lista original

Você recebeu a lista registros e precisa exibir uma versão em ordem decrescente, mas depois ainda usará registros exatamente na ordem em que foi recebida. Qual expressão atende ao requisito?

Passo 5 de 6

Usar uma função nomeada como chave

Personalize a ordenação de tarefas com uma função nomeada passada para key.

A chave extrai o valor de comparação

Função em key

Em key, passe a função, sem parênteses. Durante a ordenação, Python chama essa função uma vez para cada elemento e usa o retorno para decidir a posição.

A função de chave recebe um elemento por vez; ela não compara dois elementos diretamente.

Como key participa da ordenação

Cada dicionário continua inteiro. Apenas o valor retornado pela função é usado como chave de comparação.

Diagrama de três cartões de tarefas completos, cada um apontando para um valor numérico de duração, e os cartões reorganizados em ordem crescente.

As durações determinam a ordem; os dicionários de tarefa são preservados no resultado.

Dica

Chaves comparáveis

O retorno da função de chave precisa poder ser comparado com os demais retornos. Por exemplo, durações numéricas podem ser ordenadas entre si.

Ordenar tarefas pela duração

Uma função nomeada como chave

Execute este código no seu editor para observar os registros completos em uma nova lista.

python
tarefas = [
    {"titulo": "Enviar relatório", "duracao": 45},
    {"titulo": "Responder e-mails", "duracao": 15},
    {"titulo": "Revisar orçamento", "duracao": 30},
]


def duracao(tarefa):
    return tarefa["duracao"]


por_duracao = sorted(tarefas, key=duracao)
por_duracao_decrescente = sorted(tarefas, key=duracao, reverse=True)

print(por_duracao)
print(por_duracao_decrescente)
print(tarefas)

Exemplo

O que acontece

duracao recebe, em chamadas separadas, cada dicionário da lista e devolve 45, 15 ou 30. Em por_duracao, a ordem dos títulos é: Responder e-mails, Revisar orçamento, Enviar relatório.

Os itens de por_duracao ainda são dicionários completos. Como foi usado sorted, tarefas mantém a ordem inicial. Para alterar a própria lista, use tarefas.sort(key=duracao, reverse=True); o método retorna None.

Complete a passagem da chave

Sem executar antecipadamente

Complete a chamada para ordenar uma nova lista pela duração:

ordenadas = sorted(tarefas, key=_____)

Preveja e justifique o resultado

Registros, não apenas chaves

Considere o código:

tarefas = [
    {"titulo": "Preparar apresentação", "prioridade": 3},
    {"titulo": "Planejar reunião", "prioridade": 1},
    {"titulo": "Corrigir relatório", "prioridade": 2},
]

def prioridade(tarefa):
    return tarefa["prioridade"]

ordenadas = sorted(tarefas, key=prioridade)

Qual será a ordem dos títulos em ordenadas? Por que o resultado contém dicionários completos, em vez de somente 1, 2 e 3?

Escreva pelo menos 40 caracteres (0/40).

Passo 6 de 6

Aplicação final: ordenar tarefas por critérios diferentes

Integre funções recebidas como critérios de ordenação e compare uma nova lista ordenada com a ordenação feita na própria lista.

Uma operação, dois critérios

Passe o critério para key

A função ordenar_tarefas recebe três valores: a lista, a função que define o critério e a direção da ordem. Ela encaminha criterio para key sem parênteses, pois sorted é quem chamará essa função uma vez para cada tarefa.

As funções por_titulo e por_duracao recebem uma tarefa e devolvem, respectivamente, o título ou a duração. Trocar apenas a função fornecida muda o critério sem alterar ordenar_tarefas.

Fluxo da ordenação por critério

Diagrama mostrando uma lista de dicionários de tarefas entrando em ordenar_tarefas, a função criterio sendo encaminhada para key de sorted e uma nova lista de tarefas completas saindo ordenada.

A função de critério extrai valores para comparação; o resultado continua contendo os dicionários completos.

Exemplo autocontido

Crie um arquivo Python com este código e execute-o no seu computador.

python
def por_titulo(tarefa):
    return tarefa["titulo"]


def por_duracao(tarefa):
    return tarefa["duracao"]


def ordenar_tarefas(tarefas, criterio, decrescente=False):
    return sorted(tarefas, key=criterio, reverse=decrescente)


tarefas = [
    {"titulo": "Revisar relatório", "duracao": 45},
    {"titulo": "Enviar e-mail", "duracao": 10},
    {"titulo": "Planejar reunião", "duracao": 30},
]

por_nome = ordenar_tarefas(tarefas, por_titulo)
por_tempo = ordenar_tarefas(tarefas, por_duracao, decrescente=True)

assert [tarefa["titulo"] for tarefa in por_nome] == [
    "Enviar e-mail",
    "Planejar reunião",
    "Revisar relatório",
]
assert [tarefa["duracao"] for tarefa in por_tempo] == [45, 30, 10]
assert tarefas[0]["titulo"] == "Revisar relatório"

print("Por título:", por_nome)
print("Por duração decrescente:", por_tempo)
print("Lista original:", tarefas)

Atualizar a própria lista

Quando a ordem original deve mudar

A função acima usa sorted, portanto cria e devolve uma lista nova. A variável tarefas continua na ordem em que foi criada.

Se o requisito for reordenar a própria lista, use list.sort. Nesse caso, a chamada altera a lista e o retorno é None. Não atribua o retorno de .sort() a uma variável esperando receber uma lista.

Compare com list.sort

Acrescente este trecho após o código anterior. A cópia permite comparar os dois efeitos sem perder a lista original.

python
tarefas_para_atualizar = tarefas.copy()
retorno = tarefas_para_atualizar.sort(key=por_duracao, reverse=True)

assert retorno is None
assert [tarefa["duracao"] for tarefa in tarefas_para_atualizar] == [45, 30, 10]
assert tarefas[0]["titulo"] == "Revisar relatório"

print("Retorno de sort:", retorno)
print("Lista atualizada:", tarefas_para_atualizar)
print("Original preservada:", tarefas)

Dica

Escolha pela necessidade

Use sorted(...) quando precisa preservar a ordem da lista recebida e obter outra lista. Use .sort(...) quando é desejável atualizar a lista existente. Nas duas formas, passe por_titulo ou por_duracao para key sem ().

Aplique e explique o resultado

Relate sua verificação

No seu computador, execute os dois trechos. Depois, relate:

  1. A ordem de durações da lista devolvida por ordenar_tarefas em ordem decrescente.
  2. O que aconteceu com a lista original nessa operação.
  3. O retorno de .sort() e o estado de tarefas_para_atualizar.
  4. Onde por_duracao foi passada sem parênteses e por quê.

Escreva pelo menos 180 caracteres (0/180).

Síntese

Resumo

O que você integrou

  • Uma função pode ser fornecida como valor para personalizar outra operação.
  • A função receptora deve chamar a função recebida de uma forma compatível com seus parâmetros.
  • Em key=criterio, a função é passada sem parênteses; a ordenação a chama para cada elemento.
  • A chave define a comparação, mas os dicionários completos são preservados no resultado.
  • sorted devolve uma nova lista; list.sort altera a lista existente e devolve None.

Tutorial concluído

Parabéns! Você concluiu: Passar funções como argumentos

Você concluiu a aplicação de funções como argumentos. Agora consegue variar critérios de ordenação com funções nomeadas e escolher conscientemente entre criar uma lista ordenada ou alterar a lista existente.

Baixe o Aplicativo agora para ter acesso a + de 5000 cursos gratuitos, exercícios, certificado e muito conteúdo sem pagar nada!

  • Cursos online 100% gratuitos do início ao fim

    Milhares de cursos online em vídeo, ebooks e áudiobooks.

  • Mais de 60 mil exercícios gratuitos

    Para testar seus conhecimentos no decorrer dos cursos online

  • Certificado Digital gratuito válido em todo o Brasil

    Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail

Aplicativo Cursa na tela de ebook, na tela de curso em vídeo e na tela de exercícios do curso, mais o certificado de conclusão de curso