Python Parâmetros e Argumentos

Na aula Funções (def), a função bom_dia() fazia sempre a mesma coisa: "Bom dia, Ana!", e só. Mas a padaria tem muitos clientes, e escrever uma função para cada nome não faz sentido. O que você quer é uma função de saudação que receba o nome na hora da chamada: saudar("Ana"), saudar("Bruno"). Para isso, a função ganha parâmetros: espaços que são preenchidos a cada chamada.

Você vai aprender
  • A criar uma função que recebe informações, com um ou mais parâmetros.
  • A diferença entre parâmetro (o nome, no def) e argumento (o valor, na chamada).
  • O que o Python faz, por dentro, quando você chama saudar("Ana").
  • Por que a ordem dos argumentos importa.
  • A passar como argumento um texto, um número, uma variável, uma conta ou o que o input() leu.
  • Os erros reais: argumento faltando, argumento sobrando, ordem trocada, nome sem aspas.

A ideia: o espaço em branco da ficha

Na padaria, a Ana tem um bloco de cartões de aniversário já impressos: "Parabéns, ________! Um abraço da Padaria Pão Quente." Ela não manda imprimir um cartão diferente para cada cliente; ela preenche o espaço em branco com o nome de quem vai receber.

A função com parâmetro é esse cartão. O parâmetro é o espaço em branco, que tem um nome (nome). O argumento é o que você escreve no espaço quando usa o cartão ("Ana", "Bruno").

ParâmetroArgumento
No cartãoO espaço em branco "________"O nome escrito no espaço
Onde apareceNo def, entre os parêntesesNa chamada, entre os parênteses
Exemplodef saudar(nome):saudar("Ana")
O que éUm nome de variávelUm valor

Muita gente (inclusive programadores experientes) usa as duas palavras como se fossem a mesma coisa, e o mundo não acaba. Mas as mensagens de erro do Python usam argument (argumento), e saber a diferença ajuda a lê-las.


1. Uma função com um parâmetro

def saudar(nome):
    print(f"Bom dia, {nome}!")


saudar("Ana")
saudar("Bruno")
saudar("Dona Rosa")
$ python3 saudar.py
Bom dia, Ana!
Bom dia, Bruno!
Bom dia, Dona Rosa!
def saudar(nome):
A função saudar tem um parâmetro, chamado nome. É o espaço em branco do cartão.
print(f"Bom dia, {nome}!")
Dentro do corpo, nome é usado como uma variável qualquer. Aqui, dentro de uma f-string (aula f-strings).
saudar("Ana")
A chamada com o argumento "Ana": o valor que vai preencher o espaço.

Uma função, três saídas diferentes. O corpo é sempre o mesmo; o que muda é o valor que chega em nome.

O que acontece por dentro

Quando o Python executa saudar("Ana"), ele faz, escondido, uma atribuição antes de começar o corpo:

  1. Cria a variável nome e guarda nela o argumento: é como se executasse nome = "Ana".
  2. Executa o corpo: print(f"Bom dia, {nome}!") mostra "Bom dia, Ana!".
  3. Termina a função. A variável nome deixa de existir (você vai ver isso em Quando dá errado).
  4. Na chamada seguinte, saudar("Bruno"), tudo recomeça: nome = "Bruno", e assim por diante.

2. O argumento pode ser qualquer valor

Entre os parênteses da chamada vai qualquer coisa que produza um valor: um texto escrito ali mesmo, uma variável, uma conta.

def saudar(nome):
    print(f"Bom dia, {nome}!")


cliente = "Carla"
saudar(cliente)
saudar("Seu " + "Joaquim")
$ python3 argumento_variavel.py
Bom dia, Carla!
Bom dia, Seu Joaquim!

Na primeira chamada, o argumento é a variável cliente: o Python pega o valor dela, "Carla", e o entrega ao parâmetro nome. Os nomes não precisam combinar: lá fora a variável se chama cliente, lá dentro o parâmetro se chama nome. Na segunda, o Python primeiro faz a conta "Seu " + "Joaquim" e só depois entrega o resultado à função.

Pode até ser o que o leitor digitou. Aqui, o valor que o input() devolve (aula input()) vai direto para a função:

def saudar(nome):
    print(f"Bom dia, {nome}!")


saudar(input("Qual é o seu nome? "))
$ python3 com_input.py
Qual é o seu nome? Ana                             « a Ana digitou "Ana" e apertou Enter
Bom dia, Ana!

E dentro de um laço, a mesma função é chamada para cada item de uma lista (aula for):

def saudar(nome):
    print(f"Bom dia, {nome}!")


turma = ["Ana", "Bruno", "Carla"]
for aluno in turma:
    saudar(aluno)
$ python3 lista_nomes.py
Bom dia, Ana!
Bom dia, Bruno!
Bom dia, Carla!

Missão: a função parabens só sabe dizer "Parabéns!". Dê a ela um parâmetro, para que mostre Parabéns, Carla! e Parabéns, Bruno!, e chame-a uma vez para cada um.

def parabens():
    print("Parabéns!")


parabens()
def parabens(nome):
    print(f"Parabéns, {nome}!")


parabens("Carla")
parabens("Bruno")

3. Dois ou mais parâmetros

Uma função pode ter quantos parâmetros precisar. No def, eles são separados por vírgula; na chamada, os argumentos também:

def apresentar(nome, idade):
    print(f"{nome} tem {idade} anos.")


apresentar("Ana", 30)
apresentar("Bruno", 8)
$ python3 dois_parametros.py
Ana tem 30 anos.
Bruno tem 8 anos.

Os argumentos são entregues pela posição: o primeiro argumento vai para o primeiro parâmetro, o segundo para o segundo. Em apresentar("Ana", 30), o Python faz nome = "Ana" e idade = 30. Por isso o Python chama esses argumentos de positional arguments, "argumentos posicionais".

PosiçãoParâmetro (no def)Argumento (na chamada)
1ªnome"Ana"
2ªidade30

A ordem importa

O Python não sabe que "Ana" "parece" um nome e 30 "parece" uma idade. Ele só olha as posições. Troque a ordem e veja:

def apresentar(nome, idade):
    print(f"{nome} tem {idade} anos.")


apresentar(30, "Ana")
$ python3 ordem_trocada.py
30 tem Ana anos.

Nenhum erro: nome recebeu 30 e idade recebeu "Ana", e a f-string mostrou o que recebeu. O resultado é absurdo, mas o Python não tem como saber. Existe um jeito de dizer explicitamente quem é quem, apresentar(idade=30, nome="Ana"), que você vai ver na aula Valores Padrão e Argumentos Nomeados.

Uma conta dentro da função

A nota da padaria precisa do produto, da quantidade e do preço de cada unidade. A função faz a conta e mostra a linha:

def linha_da_nota(produto, quantidade, preco):
    total = quantidade * preco
    print(f"{produto}: {quantidade} x R$ {preco:.2f} = R$ {total:.2f}")


linha_da_nota("Pão francês", 10, 0.80)
linha_da_nota("Leite", 2, 5.50)
linha_da_nota("Bolo de milho", 1, 18)
$ python3 nota.py
Pão francês: 10 x R$ 0.80 = R$ 8.00
Leite: 2 x R$ 5.50 = R$ 11.00
Bolo de milho: 1 x R$ 18.00 = R$ 18.00
produto, quantidade, preco
Três parâmetros, três espaços para preencher. Cada chamada precisa de três argumentos, nessa ordem.
total = quantidade * preco
Os parâmetros entram em contas como qualquer variável. A variável total foi criada dentro da função.
{preco:.2f}
Mostra o número com 2 casas decimais (aula f-strings). Repare que o Python usa ponto como separador decimal, e não vírgula.

Formas diferentes de passar o argumento

Todas as chamadas abaixo entregam um valor ao parâmetro nome da mesma função saudar:

ChamadaO argumento é…Quando usar
saudar("Ana")Um valor escrito ali mesmoQuando o valor é fixo e conhecido
saudar(cliente)O valor de uma variávelO mais comum: o valor veio de outro lugar do programa
saudar("Seu " + "Joaquim")O resultado de uma contaQuando a conta é curta; se for longa, guarde-a antes numa variável com bom nome
saudar(input("Nome? "))O valor que outra função devolveuQuando o valor só é usado ali; senão, guarde numa variável
for aluno in turma: saudar(aluno)Um item da lista por vezPara fazer a mesma coisa com cada item

Quando dá errado

Faltou o argumento
def saudar(nome):
    print(f"Bom dia, {nome}!")


saudar()
$ python3 faltou.py
Traceback (most recent call last):
  File "/home/ana/faltou.py", line 5, in <module>
    saudar()
    ~~~~~~^^
TypeError: saudar() missing 1 required positional argument: 'nome'

Linha por linha:

File "/home/ana/faltou.py", line 5, in <module>
O erro foi na linha 5, no programa principal.
saudar()
A linha culpada. Os sinais embaixo mostram as partes: ~~~~~~ embaixo do nome da função, e ^^ embaixo dos parênteses, onde está o problema.
TypeError
"Erro de tipo": é o nome que o Python dá a vários erros de "usar uma coisa do jeito errado", inclusive chamar uma função com o número errado de argumentos.
saudar() missing 1 required positional argument: 'nome'
"Falta 1 argumento posicional obrigatório na saudar(): o 'nome'". O cartão tem um espaço em branco, e você não escreveu nada nele. O Python até diz o nome do parâmetro que ficou vazio.

Como consertar: passe um valor para cada parâmetro: saudar("Ana").

Quando faltam vários, a mensagem lista todos:

def linha_da_nota(produto, quantidade, preco):
    total = quantidade * preco
    print(f"{produto}: {quantidade} x R$ {preco:.2f} = R$ {total:.2f}")


linha_da_nota(10)
$ python3 faltaram_dois.py
Traceback (most recent call last):
  File "/home/ana/faltaram_dois.py", line 6, in <module>
    linha_da_nota(10)
    ~~~~~~~~~~~~~^^^^
TypeError: linha_da_nota() missing 2 required positional arguments: 'quantidade' and 'preco'

Repare: a Ana quis passar a quantidade, 10, mas ela foi parar no primeiro parâmetro, produto. Por isso o Python reclama da falta de 'quantidade' e 'preco', e não de 'produto'.

Sobrou argumento
def saudar(nome):
    print(f"Bom dia, {nome}!")


saudar("Ana", "Bruno")
$ python3 sobrou.py
Traceback (most recent call last):
  File "/home/ana/sobrou.py", line 5, in <module>
    saudar("Ana", "Bruno")
    ~~~~~~^^^^^^^^^^^^^^^^
TypeError: saudar() takes 1 positional argument but 2 were given

"saudar() recebe 1 argumento posicional, mas foram dados 2". Um espaço em branco, dois nomes: não cabe. Como consertar: chame a função uma vez para cada nome (saudar("Ana") e saudar("Bruno")) ou, se a função precisa mesmo de dois valores, acrescente um parâmetro no def.

O mesmo acontece com uma função sem parâmetros que recebe um argumento:

def bom_dia():
    print("Bom dia!")


bom_dia("Ana")
$ python3 sem_parametro.py
Traceback (most recent call last):
  File "/home/ana/sem_parametro.py", line 5, in <module>
    bom_dia("Ana")
    ~~~~~~~^^^^^^^
TypeError: bom_dia() takes 0 positional arguments but 1 was given

"bom_dia() recebe 0 argumentos, mas foi dado 1". O def bom_dia(): não tem espaço para o nome.

Ordem trocada: às vezes calado, às vezes com erro lá dentro
def total(quantidade, preco):
    print(quantidade * preco)


total(3, 2.5)
total("Pão", 3)
total(2.5, "Pão")
$ python3 trocado_conta.py
7.5
PãoPãoPão
Traceback (most recent call last):
  File "/home/ana/trocado_conta.py", line 7, in <module>
    total(2.5, "Pão")
    ~~~~~^^^^^^^^^^^^
  File "/home/ana/trocado_conta.py", line 2, in total
    print(quantidade * preco)
          ~~~~~~~~~~~^~~~~~~
TypeError: can't multiply sequence by non-int of type 'float'
  • total(3, 2.5) está certo: 3 unidades de R$ 2,50 dão 7.5.
  • total("Pão", 3) passou o nome do produto no lugar da quantidade. Não deu erro: "Pão" * 3 repete o texto 3 vezes (aula Juntar e Repetir Textos), e saiu PãoPãoPão. Um resultado errado e silencioso.
  • total(2.5, "Pão") deu erro, e o traceback agora tem dois trechos File. Leia de cima para baixo, como um caminho: o programa principal (<module>), na linha 7, chamou total; dentro de total (in total), na linha 2, a conta falhou. O último trecho é onde o erro aconteceu de fato; o de cima mostra quem chamou.
  • TypeError: can't multiply sequence by non-int of type 'float': "não dá para multiplicar uma sequência (o texto) por um número que não é inteiro, do tipo float". Repetir "Pão" 2,5 vezes não faz sentido.

O erro aparece dentro da função, mas a culpa é da chamada. Como consertar: confira a ordem dos parâmetros no def e passe os argumentos na mesma ordem.

Esquecer as aspas no argumento
def saudar(nome):
    print(f"Bom dia, {nome}!")


saudar(Ana)
$ python3 sem_aspas.py
Traceback (most recent call last):
  File "/home/ana/sem_aspas.py", line 5, in <module>
    saudar(Ana)
           ^^^
NameError: name 'Ana' is not defined. Did you mean: 'any'?

Sem aspas, Ana parece o nome de uma variável, e não existe variável Ana. A dica Did you mean: 'any'? sugere uma função embutida de nome parecido (any), que não tem nada a ver: não siga a dica às cegas. Como consertar: texto vai entre aspas: saudar("Ana").

Usar o parâmetro fora da função
def saudar(nome):
    print(f"Bom dia, {nome}!")


saudar("Ana")
print(nome)
$ python3 fora.py
Bom dia, Ana!
Traceback (most recent call last):
  File "/home/ana/fora.py", line 6, in <module>
    print(nome)
          ^^^^
NameError: name 'nome' is not defined. Did you mean: 'None'?

A saudação funcionou, mas o print(nome) da linha 6 falhou. O parâmetro nome só existe enquanto a função está rodando; quando ela termina, ele some. Fora da função, ninguém conhece esse nome. Isso tem aula própria: Escopo (global e local). Para levar um valor de dentro da função para fora, existe o return, da próxima aula.

Missão: as notas são: Ana 8, Bruno 7.5, Carla 9. Cada chamada da função boletim tem um erro diferente. Rode, leia cada mensagem e conserte as três chamadas (o def está certo).

def boletim(aluno, nota):
    print(f"{aluno} tirou {nota}.")


boletim("Ana")
boletim(7.5, "Bruno")
boletim("Carla", 9, 10)
def boletim(aluno, nota):
    print(f"{aluno} tirou {nota}.")


boletim("Ana", 8)
boletim("Bruno", 7.5)
boletim("Carla", 9)

Referência rápida

EscritaO que faz
def f(a):Função com um parâmetro, a
def f(a, b, c):Função com três parâmetros, separados por vírgula
f(10)Chama f com o argumento 10: antes do corpo, o Python faz a = 10
f(x, y, z)Argumentos posicionais: o 1º vai para o 1º parâmetro, o 2º para o 2º…
f(variavel)Entrega o valor da variável; o nome dela não precisa ser igual ao do parâmetro
MensagemCausa provável
missing 1 required positional argument: 'x'Faltou argumento na chamada
takes 1 positional argument but 2 were givenSobrou argumento (ou faltou parâmetro no def)
takes 0 positional arguments but 1 was givenA função não tem parâmetros, e a chamada passou um valor
Resultado absurdo, sem erroArgumentos na ordem errada
NameError: name 'Ana' is not definedTexto sem aspas no argumento
NameError com o nome do parâmetro, fora da funçãoO parâmetro só existe dentro da função

Exercícios

1. O espaço em branco

Complete o parâmetro para que a função funcione:

def dobro():
    print(numero * 2)

2. Quantos argumentos?

A função começa com def pedido(cliente, produto, quantidade):. Quantos argumentos a chamada precisa ter?

3. Em def saudar(nome): e saudar("Ana"), quem é o parâmetro e quem é o argumento?

4. O que mostra apresentar(8, "Bruno"), se a função é def apresentar(nome, idade): print(f"{nome} tem {idade} anos.")?

5. Qual chamada causa TypeError: saudar() missing 1 required positional argument: 'nome'?

Missão final: a etiqueta de preço

Missão: crie uma função etiqueta com dois parâmetros, o produto e o preço, que mostre a etiqueta no formato Café - R$ 4.00 (preço com 2 casas). Chame-a para o Café (4) e para o Pão de queijo (3.5).

# crie a função etiqueta aqui


# e chame-a duas vezes aqui
def etiqueta(produto, preco):
    print(f"{produto} - R$ {preco:.2f}")


etiqueta("Café", 4)
etiqueta("Pão de queijo", 3.5)

Resumo

  • O parâmetro é o nome entre os parênteses do def: o espaço em branco. O argumento é o valor entre os parênteses da chamada.
  • Na chamada, o Python faz parametro = argumento e só então executa o corpo.
  • O argumento pode ser um valor, uma variável, uma conta, o resultado de outra função.
  • Vários parâmetros se separam por vírgula, e os argumentos posicionais são entregues na ordem. Ordem trocada não dá erro: dá resultado errado (ou um erro lá dentro da função).
  • Argumento a menos: missing … required positional argument. A mais: takes N positional argument but M were given.
  • O parâmetro só existe dentro da função. Para trazer um resultado de dentro para fora, use o return, a próxima aula.