Argumentos de funções em Python: *args, **kwargs e valores padrão
Este tutorial foi traduzido do original em inglês.Read in EnglishLeer en españolЧитать на русскомอ่านภาษาไทยAvisar sobre um erro de tradução
Pense em pedir um café. Você sempre precisa escolher o tamanho: isso é obrigatório. Mas e os extras, como leite de aveia, uma dose extra de espresso ou calda de caramelo? Esses são opcionais. Você só fala deles quando quer.
Os argumentos de funções em Python funcionam do mesmo jeito. Alguns são obrigatórios, outros têm valores padrão sensatos, e alguns permitem passar quantos extras você quiser. Dominar esses padrões é o que separa um iniciante de alguém que escreve código realmente flexível.
Neste tutorial, você vai aprender todas as formas que o Python oferece para passar dados para funções, desde os argumentos posicionais básicos até os poderosos padrões *args e **kwargs, usados em bibliotecas do mundo real.
Argumentos posicionais versus argumentos nomeados
Quando você chama uma função, o Python associa os argumentos aos parâmetros de duas formas. Argumentos posicionais são associados pela posição: o primeiro argumento vai para o primeiro parâmetro. Argumentos nomeados (keyword arguments) são associados pelo nome.
Whiskers is a cat Buddy is a dog
Com argumentos nomeados, você escreve parameter_name=value. Isso deixa a chamada autoexplicativa: qualquer pessoa que leia o código vê exatamente o que cada valor significa, mesmo sem olhar a definição da função.
Você pode misturar os dois estilos na mesma chamada, mas os argumentos posicionais precisam vir antes dos nomeados.
Whiskers is a 3-year-old cat
Como os valores padrão deixam as funções flexíveis
Valores padrão permitem definir parâmetros opcionais. Se quem chama a função fornece um valor, ele é usado. Se não, entra o valor padrão.
large coffee medium coffee with oat milk small coffee with almond milk, 2 sugar(s)
O parâmetro size não tem valor padrão: ele é obrigatório. Os parâmetros milk e sugar têm valores padrão, então são opcionais. É exatamente assim que muitas bibliotecas Python reais funcionam: poucos parâmetros obrigatórios e muitos opcionais, com valores padrão sensatos.
A armadilha do valor padrão mutável
Essa é uma das pegadinhas mais famosas do Python. Quando você usa um objeto mutável (como uma lista) como valor padrão, esse objeto é criado uma única vez, quando a função é definida, e não a cada chamada da função.
Isso significa que todas as chamadas compartilham a mesma lista. As mudanças feitas em uma chamada passam para a próxima. Veja na prática:
['apples'] ['apples', 'bread'] ['apples', 'bread', 'milk']
Surpreso? Cada chamada deveria começar com uma lista nova, mas a lista continua crescendo. Isso acontece porque [] é criada uma vez, no momento em que a função é definida, e reutilizada em todas as chamadas.
A correção é um padrão bem conhecido em Python: use None como valor padrão e crie uma lista nova dentro da função.
['apples'] ['bread'] ['milk']
Para que serve o *args?
Às vezes você não sabe de antemão quantos argumentos uma função vai receber. Talvez você queira uma função que some qualquer quantidade de números: 2, 5 ou 100.
A sintaxe *args reúne todos os argumentos posicionais extras em uma tupla. Depois você pode percorrê-los, acessá-los por índice ou fazer com eles qualquer coisa que faria com uma tupla.
6 100 5
O nome args é só uma convenção. Você poderia escrever *numbers, *items ou *values. A mágica está no *: ele diz ao Python para empacotar todos os argumentos posicionais restantes em uma tupla.
<class 'tuple'>
('hello', 42, True)
Argument 0: hello
Argument 1: 42
Argument 2: TrueVocê pode combinar *args com parâmetros comuns. Os parâmetros comuns pegam seus valores primeiro, e depois *args reúne tudo o que sobrou.
Hello, Alice! Hello, Bob! Hello, Charlie!
Para que serve o **kwargs?
Enquanto *args reúne argumentos posicionais extras, **kwargs reúne argumentos nomeados extras em um dicionário. As chaves são os nomes dos argumentos, e os valores são os valores dos argumentos.
name: Alice age: 25 city: Paris
Assim como args, o nome kwargs é só uma convenção. Você poderia escrever **info, **options ou **settings. O que importa é o **: ele diz ao Python para empacotar os argumentos nomeados extras em um dicionário.
Isso é extremamente útil em funções que precisam ser flexíveis. Você pode passar quaisquer dados com nome sem mudar a definição da função.
Username: alice_99 email: alice@mail.com age: 25 Username: bob_42 city: London
Combinando todos os tipos de argumento
Você pode usar parâmetros comuns, valores padrão, *args e **kwargs na mesma função. Mas a ordem importa. O Python exige esta sequência:
*argsdelivery=False no exemplo abaixo: depois de *args, eles só podem ser passados pelo nome**kwargsOrder from: Pizza Palace Items: margherita, garlic bread Delivery: True tip: 5 note: extra cheese
def process(*args, **kwargs):
# What does this expect?
passdef process(data, format='json',
verbose=False):
# Easy to understand
passExercícios práticos
O que este código exibe? Digite a saída exata.
def power(base, exponent=2):
print(base ** exponent)
power(5)
power(2, 10)
power(exponent=3, base=4)Escreva uma função chamada greet que receba um parâmetro name e um parâmetro opcional greeting com valor padrão 'Hello'. Ela deve exibir <greeting>, <name>!. Por exemplo, greet('Alice') exibe Hello, Alice! e greet('Bob', 'Hey') exibe Hey, Bob!.
Escreva uma função chamada sum_all que use *args para aceitar qualquer quantidade de argumentos numéricos e retorne a soma deles. Se nenhum argumento for passado, retorne 0.
Esta função deveria criar uma lista nova a cada chamada, mas tem o bug do valor padrão mutável. Corrija-a para que cada chamada comece com uma lista nova.
Saída esperada:
[1]
[2]
[3]Escreva uma função chamada build_profile que receba um parâmetro obrigatório name e use **kwargs para aceitar qualquer informação adicional. Ela deve exibir o nome na primeira linha e depois cada par chave-valor nas linhas seguintes, no formato key: value (com dois espaços no início). Exiba as chaves na ordem em que foram passadas.
Exemplo: build_profile('Alice', age=25, city='NYC') deve exibir:
Alice
age: 25
city: NYCEscreva uma função chamada calc que receba uma string operation ('add', 'multiply' ou 'max') e depois qualquer quantidade de argumentos numéricos usando *args. Ela deve retornar o resultado:
'add': a soma de todos os números (0 se não houver nenhum)'multiply': o produto de todos os números (1 se não houver nenhum)'max': o maior número (0 se não houver nenhum)Exemplos: calc('add', 1, 2, 3) retorna 6. calc('multiply', 2, 3, 4) retorna 24.
Reescreva a função abaixo para usar **kwargs em vez de parâmetros individuais. A função deve aceitar name como parâmetro obrigatório e todo o resto por meio de **kwargs. Exiba o nome e depois cada detalhe em sua própria linha, no formato key: value. A saída precisa ser exatamente igual.
Original:
def show_student(name, grade, school, gpa):
print(name)
print('grade: ' + str(grade))
print('school: ' + school)
print('gpa: ' + str(gpa))Saída esperada para show_student('Alice', grade=10, school='Lincoln', gpa=3.8):
Alice
grade: 10
school: Lincoln
gpa: 3.8