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.
- 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âmetro | Argumento | |
|---|---|---|
| No cartão | O espaço em branco "________" | O nome escrito no espaço |
| Onde aparece | No def, entre os parênteses | Na chamada, entre os parênteses |
| Exemplo | def saudar(nome): | saudar("Ana") |
| O que é | Um nome de variável | Um 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
saudartem um parâmetro, chamadonome. É 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:
- Cria a variável
nomee guarda nela o argumento: é como se executassenome = "Ana". - Executa o corpo:
print(f"Bom dia, {nome}!")mostra "Bom dia, Ana!". - Termina a função. A variável
nomedeixa de existir (você vai ver isso em Quando dá errado). - 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ção | Parâmetro (no def) | Argumento (na chamada) |
|---|---|---|
| 1ª | nome | "Ana" |
| 2ª | idade | 30 |
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
totalfoi 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:
| Chamada | O argumento é… | Quando usar |
|---|---|---|
saudar("Ana") | Um valor escrito ali mesmo | Quando o valor é fixo e conhecido |
saudar(cliente) | O valor de uma variável | O mais comum: o valor veio de outro lugar do programa |
saudar("Seu " + "Joaquim") | O resultado de uma conta | Quando a conta é curta; se for longa, guarde-a antes numa variável com bom nome |
saudar(input("Nome? ")) | O valor que outra função devolveu | Quando o valor só é usado ali; senão, guarde numa variável |
for aluno in turma: saudar(aluno) | Um item da lista por vez | Para fazer a mesma coisa com cada item |
Quando dá errado
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'.
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.
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" * 3repete o texto 3 vezes (aula Juntar e Repetir Textos), e saiuPãoPãoPão. Um resultado errado e silencioso.total(2.5, "Pão")deu erro, e o traceback agora tem dois trechosFile. Leia de cima para baixo, como um caminho: o programa principal (<module>), na linha 7, chamoutotal; dentro detotal(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 tipofloat". 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.
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").
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
| Escrita | O 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 |
| Mensagem | Causa provável |
|---|---|
missing 1 required positional argument: 'x' | Faltou argumento na chamada |
takes 1 positional argument but 2 were given | Sobrou argumento (ou faltou parâmetro no def) |
takes 0 positional arguments but 1 was given | A função não tem parâmetros, e a chamada passou um valor |
| Resultado absurdo, sem erro | Argumentos na ordem errada |
NameError: name 'Ana' is not defined | Texto sem aspas no argumento |
NameError com o nome do parâmetro, fora da função | O 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:
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 = argumentoe 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.