Fundamentos
Parâmetros e argumentos em Python: posicionais, nomeados, valores padrão e *args
Aprenda a passar valores para funções em Python: parâmetros e argumentos, posição e nome, valores padrão, *args e as armadilhas mais comuns.
Por Prof. Rodrigo Faustino · Atualizado em · 14 min de leitura
Parâmetro é o nome que a função declara no cabeçalho, e argumento é o valor que a chamada coloca nesse nome. Os argumentos podem ser passados por posição, na ordem em que os parâmetros foram escritos, ou por nome, com parametro=valor. Um parâmetro pode ter valor padrão, que vale quando a chamada não manda nada, e um parâmetro com asterisco, como *args, recolhe quantos argumentos sobrarem numa tupla.
No artigo anterior as funções tinham os parênteses vazios, como saudar(), e faziam sempre a mesma coisa. Com parâmetros, a mesma função trabalha com valores diferentes a cada chamada: piscar três vezes ou duas, saudar a Ana ou o Rui, somar três números ou cinco. Este artigo mostra as quatro formas de passar valores, o que muda no corpo da função, os erros que cada forma provoca e como isso aparece em programas de ESP32.
Parâmetro e argumento
Os dois nomes confundem muita gente porque descrevem a mesma conexão vista de lados diferentes. O parâmetro mora na definição, entre os parênteses do def, e é um nome para um valor que ainda não existe. O argumento mora na chamada, e é o valor de verdade. Quando a chamada acontece, o Python liga cada argumento a um parâmetro, e dentro da função o parâmetro se comporta como uma variável que já começa com o valor recebido.
def piscar(vezes, pausa):
print("piscar", vezes, "vezes com pausa de", pausa)
piscar(3, 0.5)
piscar(2, 0.1)
v = 5
p = 0.25
piscar(v, p)A saída é piscar 3 vezes com pausa de 0.5, piscar 2 vezes com pausa de 0.1 e piscar 5 vezes com pausa de 0.25. O argumento pode ser um número escrito na hora, como nas duas primeiras chamadas, ou uma variável, como na terceira. O nome da variável da chamada não precisa ser o mesmo do parâmetro: v e p chegam dentro da função como vezes e pausa.
Uma consequência que costuma surpreender: mudar o parâmetro dentro da função não muda a variável de fora.
def dobrar(n):
n = n * 2
print("dentro", n)
n = 5
dobrar(n)
print("fora", n)
x = 7
dobrar(x)
print("x continua", x)A saída é dentro 10, fora 5, dentro 14 e x continua 7. O n de dentro e o n de fora têm o mesmo nome por coincidência e são variáveis diferentes. Na chamada, a função recebeu o valor 5 e criou o próprio n, que sumiu quando a função terminou. O artigo sobre escopo detalha as regras. Por enquanto, guarde que passar um valor não dá à função o poder de alterar a variável original.
Da ementa ao semestre planejado
- Plano de ensino e calendário montados sozinhos
- Diário de aulas pronto para colar no SIGA
- Slides e listas de exercícios com gabarito
Versão Community grátis · Windows
Argumentos posicionais
O jeito mais simples de passar valores é pela posição: o primeiro argumento vai para o primeiro parâmetro, o segundo para o segundo, e assim por diante.
def intervalo(inicio, fim):
print("de", inicio, "ate", fim)
intervalo(2, 10)
intervalo(10, 2)A saída é de 2 ate 10 e de 10 ate 2. A segunda chamada não dá erro, e esse é o problema: com argumentos trocados, o programa roda e entrega um resultado errado. Com os parâmetros de tipos diferentes, o erro costuma aparecer logo, mas com dois números a troca passa batida.
def dividir(a, b):
print(a, "/", b, "=", a / b)
dividir(10, 4)
dividir(4, 10)A saída é 10 / 4 = 2.5 e 4 / 10 = 0.4. Quando a ordem importa, como na divisão, vale conferir a definição antes de chamar. Em funções com quatro ou cinco parâmetros, a posição deixa de ser confiável de cabeça, e é aí que entram os argumentos nomeados.
Argumentos nomeados
Na chamada, o argumento pode vir acompanhado do nome do parâmetro, e então a posição não decide mais nada:
def intervalo(inicio, fim):
print("de", inicio, "ate", fim)
intervalo(2, 10)
intervalo(fim=10, inicio=2)
intervalo(2, fim=10)As três chamadas dão de 2 ate 10. Na segunda, os dois argumentos têm nome e a ordem é livre. Na terceira, o primeiro vai por posição e o segundo por nome, o que é permitido desde que os posicionais venham antes dos nomeados.
Vale usar o nome na chamada quando o valor sozinho não explica nada. piscar(3, 0.5, 4) obriga o leitor a abrir a definição para saber o que são 3, 0.5 e 4. Já piscar(vezes=3, pausa=0.5, pino=4) se lê sozinha. Você já faz isso com funções prontas, como em print("a", "b", sep="-"): o sep é um parâmetro nomeado do print, assim como o end.
Existem três erros típicos com nomes. O primeiro é dar o mesmo parâmetro duas vezes, por posição e por nome:
def piscar(vezes, pausa=0.2):
print(vezes, pausa)
piscar(3, vezes=2)Traceback (most recent call last):
File "main.py", line 4, in <module>
TypeError: function got multiple values for argument 'vezes'O 3 foi para vezes por posição, e o vezes=2 tentou preencher o mesmo lugar. O segundo é usar um nome que a função não tem:
def piscar(vezes, pausa=0.2):
print(vezes, pausa)
piscar(3, tempo=1)Traceback (most recent call last):
File "main.py", line 4, in <module>
TypeError: unexpected keyword argument 'tempo'O terceiro é botar um argumento posicional depois de um nomeado, o que o Python recusa antes mesmo de executar:
def piscar(vezes, pausa=0.2):
print(vezes, pausa)
piscar(vezes=3, 0.5)Traceback (most recent call last):
File "main.py", line 4
SyntaxError: positional arg after keyword argO Python do computador diz positional argument follows keyword argument e o do simulador usa a forma curta. Nos três casos a leitura é a mesma: o erro está na linha da chamada, e a solução é olhar a definição.
Valores padrão
Um parâmetro pode ter um valor padrão, escrito com = no cabeçalho. Se a chamada não mandar nada para ele, o padrão entra no lugar:
def saudar(nome, saudacao="ola"):
print(saudacao + ",", nome)
saudar("Ana")
saudar("Rui", "bom dia")
saudar("Bia", saudacao="boa noite")
saudar(saudacao="oi", nome="Leo")A saída é ola, Ana, bom dia, Rui, boa noite, Bia e oi, Leo. O nome é obrigatório, e a saudacao é opcional. Na primeira chamada ela vale o padrão, nas outras duas é trocada, por posição e por nome, e na última os dois argumentos vão por nome, na ordem inversa.
A tabela da figura mostra a mesma função, piscar(vezes, pausa=0.2, pino=2), em seis chamadas. piscar(3) usa dois padrões. piscar(3, 0.5) troca o segundo valor por posição. piscar(3, pino=4) pula a pausa e troca só o pino, que é a grande vantagem do argumento nomeado: ele permite alterar um padrão do meio ou do fim sem repetir os que vêm antes. As duas últimas linhas são erros, o primeiro por falta de vezes, que não tem padrão, e o segundo por vezes repetido.
def piscar(vezes, pausa=0.2, pino=2):
print("vezes", vezes, "pausa", pausa, "pino", pino)
piscar(3)
piscar(3, 0.5)
piscar(3, pino=4)
piscar(pausa=0.1, vezes=2)
piscar(1, 0.3, 5)A saída é vezes 3 pausa 0.2 pino 2, vezes 3 pausa 0.5 pino 2, vezes 3 pausa 0.2 pino 4, vezes 2 pausa 0.1 pino 2 e vezes 1 pausa 0.3 pino 5, uma linha para cada chamada.
Há uma regra de ordem na definição: os parâmetros obrigatórios vêm antes dos que têm padrão. Escrever o contrário é erro de sintaxe:
def piscar(pausa=0.2, vezes):
print(vezes, pausa)Traceback (most recent call last):
File "main.py", line 1
SyntaxError: non-default argument follows default argumentA razão é prática. Numa chamada como piscar(3), o Python não teria como saber se o 3 é a pausa ou as vezes. Colocando os obrigatórios primeiro, a posição sempre tem resposta.
Um exemplo do dia a dia é o preço com quantidade e desconto opcionais:
def total(preco, qtd=1, desconto=0):
print(preco * qtd - desconto)
total(10)
total(10, 3)
total(10, 3, 5)
total(10, desconto=2)
total(10, 3, desconto=5)A saída é 10, 30, 25, 8 e 25. Sem opcionais, a função vale para o caso mais comum, e quem precisa de mais controle manda só o que muda.
A IA que lembra da sua vida e mora no seu computador
- Memória de longo prazo com a fonte de cada resposta
- Funciona offline: seus dados ficam no seu PC
- Lê PDFs, slides, fotos e gravações de reunião
Plano Essencial grátis para sempre
Quantidade variável com *args
Às vezes não se sabe quantos valores virão: somar três notas, cinco leituras ou duas. Um parâmetro com asterisco antes do nome recolhe todos os argumentos posicionais que sobrarem numa tupla:
def somar(*numeros):
print(numeros, type(numeros))
total = 0
for n in numeros:
total = total + n
print("soma", total)
somar(4, 7, 9)
somar(5)
somar()
lista = [1, 2, 3]
somar(*lista)A saída tem quatro blocos de duas linhas. Para somar(4, 7, 9), mostra (4, 7, 9) <class 'tuple'> e soma 20. Para somar(5), (5,) <class 'tuple'> e soma 5. Para somar(), () <class 'tuple'> e soma 0. Para somar(*lista), (1, 2, 3) <class 'tuple'> e soma 6. O corpo da função trata numeros como um grupo qualquer e usa um for, como nos artigos sobre laços. A tupla de um elemento só é escrita (5,), com a vírgula, e a tupla vazia, (), é aceita: chamar sem nenhum argumento não é erro.
O asterisco tem dois sentidos, conforme o lugar em que aparece. Na definição, ele reúne: *numeros junta os argumentos extras numa tupla. Na chamada, ele espalha: somar(*lista) entrega os itens da lista como se cada um tivesse sido escrito separado, somar(1, 2, 3). A palavra args é só a convenção, e *numeros ou *notas funcionam do mesmo jeito, com o nome que explicar melhor o conteúdo.
Dá para combinar parâmetros fixos com o asterisco. Os fixos vêm antes e recebem os primeiros valores. O que sobrar vai para a tupla:
def media(primeiro, *resto):
soma = primeiro
for n in resto:
soma = soma + n
print("media", soma / (1 + len(resto)), "de", 1 + len(resto))
media(8)
media(8, 6)
media(8, 6, 7)A saída é media 8.0 de 1, media 7.0 de 2 e media 7.0 de 3. Aqui o primeiro é obrigatório. Chamar media() sem nada daria TypeError, o que é desejado: média de zero valores não faz sentido, e a função se recusa a calcular.
Depois do *resto, um parâmetro só pode ser preenchido por nome. Isso é útil para opções que não devem ser confundidas com os valores do grupo:
def unir(*partes, sep="-"):
texto = ""
for i in range(len(partes)):
if i > 0:
texto = texto + sep
texto = texto + str(partes[i])
print(texto)
unir("a", "b", "c")
unir("a", "b", "c", sep="/")
unir(1, 2)
print("a", "b", "c", sep="-")
print("x", "y", end="!")
print()A saída é a-b-c, a/b/c, 1-2, a-b-c e x y!. O print que você usa desde o começo da série é construído com a mesma ideia: aceita qualquer número de valores e tem os nomeados sep e end. Uma consequência é que o * pega só argumentos soltos, e não um grupo inteiro dentro de uma lista:
def somar(*numeros):
print(sum(numeros))
somar([1, 2, 3])Traceback (most recent call last):
File "main.py", line 4, in <module>
File "main.py", line 2, in somar
TypeError: unsupported types for __add__: 'int', 'list'A chamada passou um argumento só, a lista, e numeros virou ([1, 2, 3],), uma tupla com uma lista dentro. O sum tentou somar 0 com a lista e falhou. O conserto é espalhar com o asterisco na chamada, somar(*[1, 2, 3]), ou chamar sem lista, somar(1, 2, 3). O Python do computador escreve a mensagem como unsupported operand type(s) for +: 'int' and 'list'.
Existe ainda uma versão para argumentos nomeados que sobram, com dois asteriscos, e o nome que se usa por convenção é **kwargs. Ela reúne os nomeados num dicionário:
def mostrar(**dados):
print(dados)
for chave in dados:
print(chave, "=", dados[chave])
mostrar(nome="Ana", idade=20)
mostrar()A saída é {'nome': 'Ana', 'idade': 20}, nome = Ana, idade = 20 e {}. É menos comum em programas didáticos. Serve para funções que repassam opções a outras, e basta saber que existe.
Na ESP32
Em hardware, os valores padrão tornam as funções convenientes. Os dados que quase nunca mudam, como a pausa e a quantidade de piscadas, ficam como padrão, e quem precisar de outro valor manda só esse. O pino, que muda de montagem para montagem, é o primeiro parâmetro e obrigatório:
from machine import Pin
import time
def piscar(pino, vezes=3, pausa=0.1):
led = Pin(pino, Pin.OUT)
for i in range(vezes):
led.on()
time.sleep(pausa)
led.off()
time.sleep(pausa)
print("pino", pino, "piscadas", vezes)
piscar(2)
piscar(2, 2)
piscar(4, vezes=1, pausa=0.05)O Serial mostra pino 2 piscadas 3, pino 2 piscadas 2 e pino 4 piscadas 1. A função cria o Pin com o número que recebeu, então a mesma função serve para qualquer LED. O Pin(pino, Pin.OUT) é também uma chamada com dois argumentos posicionais, e o segundo, Pin.OUT, é o modo do pino. Ler a documentação de uma função pronta é, em boa parte, ler a lista de parâmetros e descobrir quais têm padrão. Nos artigos sobre PWM, ADC e I2C aparecem outras funções e classes prontas, e vale conferir, em cada uma, quais argumentos são obrigatórios e quais têm padrão.
Armadilhas que o Python não acusa
Os erros vistos até aqui avisam na hora. Dois casos não avisam.
O valor padrão que lembra da chamada anterior
O valor padrão é criado uma vez, quando o def roda, e não a cada chamada. Com números e textos, que não se alteram no lugar, isso não aparece. Com uma lista, aparece:
def acumular(x, lista=[]):
lista.append(x)
print(lista)
acumular(1)
acumular(2)
acumular(3)
print("---")
def acumular2(x, lista=None):
if lista is None:
lista = []
lista.append(x)
print(lista)
acumular2(1)
acumular2(2)A saída é [1], [1, 2], [1, 2, 3], a separação e depois [1] e [2]. Na primeira versão, a lista do padrão é sempre a mesma, e cada chamada acrescenta a ela. A segunda usa None como sinal de "não mandaram nada" e cria a lista dentro da função, o que dá uma lista nova a cada chamada. A regra: nunca use lista, dicionário ou conjunto vazio como valor padrão. Use None e crie dentro.
Argumentos na ordem errada
Duas variáveis do mesmo tipo trocadas de lugar produzem um resultado errado e nenhuma mensagem. O que ajuda é nomear: dividir(a=4, b=10) documenta a intenção, e intervalo(inicio=2, fim=10) não deixa dúvida.
Contagem errada de argumentos
Sem os nomes, o erro que mais aparece é o TypeError de contagem. Os dois sentidos são:
def piscar(vezes, pausa=0.2):
print(vezes, pausa)
piscar()Traceback (most recent call last):
File "main.py", line 4, in <module>
TypeError: function takes 1 positional arguments but 0 were givendef piscar(vezes, pausa=0.2):
print(vezes, pausa)
piscar(1, 2, 3)Traceback (most recent call last):
File "main.py", line 4, in <module>
TypeError: function takes 2 positional arguments but 3 were givenO Python do computador é mais claro: piscar() missing 1 required positional argument: 'vezes' no primeiro caso e piscar() takes from 1 to 2 positional arguments but 3 were given no segundo. O sentido é o mesmo, faltou ou sobrou argumento, e a linha apontada é a da chamada.
Em sala de aula: onde parâmetros costumam tropeçar
Estes casos se repetem nas turmas.
Parâmetro e argumento tratados como a mesma coisa
Quando o aluno diz "o parâmetro 5", ele misturou os dois. A pergunta de conferência: isto está no def ou na chamada? No def é parâmetro, na chamada é argumento.
Ler o valor com input dentro da função
Em vez de receber o número como parâmetro, a função chama input() dentro dela. Funciona uma vez e não serve para mais nada: não dá para chamar com um valor que já existe, nem testar sem digitar. A função recebe os dados, e quem lê o input é o programa principal.
Usar uma variável de fora em vez de receber parâmetro
A função usa largura e altura que estão no programa, sem receber nada. Roda, até que alguém muda o nome da variável de fora e a função quebra, ou tenta usá-la em dois retângulos diferentes. O sinal de alerta é uma função que só funciona se existir uma variável com um nome específico fora dela.
Mudar o parâmetro e esperar que a variável de fora mude
É o caso do dobrar(n): o aluno vê o valor mudar dentro da função, olha a variável de fora e acha que o computador "esqueceu". O parâmetro é uma cópia do valor, como mostrou o exemplo.
Colocar o valor padrão antes do obrigatório
O erro de sintaxe é claro, mas o aluno costuma "consertar" tirando o padrão e deixando os dois obrigatórios, e perde o benefício. A solução é reordenar: obrigatórios primeiro.
Lista como valor padrão
O caso do acumular. O primeiro teste funciona, o segundo mostra um resultado "sujo" que o aluno atribui a um defeito do computador. Quem já passou por isso uma vez lembra do None para sempre.
Tudo em *args
Quem acabou de descobrir o asterisco passa a escrever def f(*args) em tudo, e a função perde o contrato: ninguém sabe quantos valores ela espera, nem o que significam. O *args é para quando a quantidade varia de verdade.
Exercício: tabuada e média com opções
Escreva uma função tabuada(n, ate=10) que mostra a tabuada de n de 1 até ate, e uma função mostrar_media(*notas) que mostra a média das notas recebidas, ou sem notas se nenhuma vier.
def tabuada(n, ate=10):
for i in range(1, ate + 1):
print(n, "x", i, "=", n * i)
tabuada(3, 4)
print("---")
tabuada(2, ate=3)
print("---")
def mostrar_media(*notas):
if len(notas) == 0:
print("sem notas")
return
print("media", sum(notas) / len(notas))
mostrar_media(8, 6, 7)
mostrar_media()A saída é a tabuada do 3 de 1 a 4, a do 2 de 1 a 3, media 7.0 e sem notas. O return sem valor, na função da média, só encerra a função cedo; o artigo seguinte trata do return completo. Para melhorar, faça tabuada aceitar também um inicio=1 e, na média, pense no que deve acontecer se alguém mandar uma nota negativa.
Perguntas frequentes
Qual a diferença entre parâmetro e argumento?
Parâmetro é o nome na definição, argumento é o valor na chamada. Na prática, as duas palavras se misturam na conversa, e o que importa é saber de que lado da conexão se está falando.
Posso misturar posicionais e nomeados na mesma chamada?
Pode, desde que os posicionais venham primeiro. piscar(3, pino=4) funciona, e piscar(vezes=3, 0.5) é erro de sintaxe.
Por que não se escreve espaço em volta do = nos padrões?
É uma convenção de estilo do Python: pausa=0.2 e sep="-" sem espaços, tanto na definição quanto na chamada. Funciona com espaços, mas fora do costume.
O nome tem que ser args?
Não. O que vale é o asterisco. O nome args é costume, e um nome melhor, como notas, deixa o código mais legível.
Quantos parâmetros uma função deve ter?
Não existe número mágico, mas funções com mais de quatro ou cinco parâmetros costumam estar fazendo coisas demais. Quando isso acontecer, vale perguntar se a função não deveria ser dividida em duas.
*args e **kwargs funcionam na ESP32?
Funcionaram no simulador, e o MicroPython segue a mesma sintaxe do Python nesse ponto. As mensagens de erro de contagem de argumentos são mais curtas que as do computador.
Para continuar
Para praticar, o desafio Área do Retângulo pede a função area(largura, altura) com dois argumentos posicionais, e a Calculadora com Funções pede duas funções que recebem a e b. As duas usam return, que é o assunto do próximo artigo, mas a parte dos parâmetros já dá para ler agora. Se quiser rever a base, volte ao artigo sobre funções e def, e a trilha Lógica com Python reúne todos os desafios.
O próximo artigo trata do return: como a função devolve um valor para quem a chamou, como devolver mais de um e por que print e return não são a mesma coisa.