O que são * args e ** kwargs em Python?

Funções são vida. Certo? Se você começou a aprender Python, não importa se essa é sua primeira linguagem de programação ou se você veio para Python de outra linguagem, já sabe que o número de parâmetros na declaração da função corresponde ao número de argumentos que a função passa quando é chamada.



Estes são os princípios. É isso que ajuda as pessoas a entender o mundo ao seu redor. Mas a declaração "o número de parâmetros é igual ao número de argumentos" coloca uma bomba-relógio na cabeça do iniciante, que dispara depois que ele vê as misteriosas construções *args ou **kwargs na declaração de função.

Não deixe nenhum emblema levar você ao estupor. Não há nada arcaico aqui. Em geral, se esses designs não lhe são familiares, sugiro que você lide com eles.

Argumentos posicionais e nomeados


Para lidar com *args e **kwargs , precisamos dominar os conceitos de argumentos posicionais e nomeados.

Primeiro, vamos falar sobre como eles diferem. Na função mais simples, simplesmente mapeamos as posições dos argumentos e parâmetros. O argumento nº 1 corresponde ao parâmetro nº 1, o argumento nº 2 ao parâmetro nº 2 e assim por diante.

 def printThese(a,b,c):   print(a, "is stored in a")   print(b, "is stored in b")   print(c, "is stored in c") printThese(1,2,3) """ 1 is stored in a 2 is stored in b 3 is stored in c """ 

Para chamar uma função, todos os três argumentos são necessários. Se você pular pelo menos um deles, uma mensagem de erro será exibida.

 def printThese(a,b,c):   print(a, "is stored in a")   print(b, "is stored in b")   print(c, "is stored in c") printThese(1,2) """ TypeError: printThese() missing 1 required positional argument: 'c' """ 

Se você atribuir um valor padrão ao parâmetro ao declarar uma função, não será mais necessário indicar o argumento correspondente ao chamar a função. O parâmetro se torna opcional.

 def printThese(a,b,c=None):   print(a, "is stored in a")   print(b, "is stored in b")   print(c, "is stored in c") printThese(1,2) """ 1 is stored in a 2 is stored in b None is stored in c """ 

Parâmetros opcionais também podem ser definidos ao chamar uma função usando seus nomes.

No exemplo a seguir, definiremos os três parâmetros para o valor padrão None e veremos como eles podem ser atribuídos usando seus nomes e não prestando atenção à ordem dos argumentos usados ​​ao chamar a função.

 def printThese(a=None,b=None,c=None):   print(a, "is stored in a")   print(b, "is stored in b")   print(c, "is stored in c") printThese(c=3, a=1) """ 1 is stored in a None is stored in b 3 is stored in c """ 

Operador Asterisk


O operador * é mais frequentemente associado à operação de multiplicação em pessoas, mas em Python tem outro significado.

Este operador permite “descompactar” objetos dentro dos quais certos elementos estão armazenados. Aqui está um exemplo:

 a = [1,2,3] b = [*a,4,5,6] print(b) # [1,2,3,4,5,6] 

Aqui, o conteúdo da lista a obtido, descompactado e colocado na lista b .

Como usar * args e ** kwargs


Portanto, sabemos que o operador "asterisco" no Python é capaz de "retirar" seus elementos constituintes dos objetos. Também sabemos que existem dois tipos de funções de parâmetro. É possível que você já tenha pensado nisso, mas por precaução, direi isso. Ou seja, *args é uma abreviação de "argumentos" (argumentos) e ** kwargs é uma abreviação de "argumentos da palavra-chave" (argumentos nomeados).

Cada uma dessas construções é usada para descompactar argumentos do tipo correspondente, permitindo chamar funções com uma lista de argumentos de comprimento variável. Por exemplo - crie uma função que possa exibir os resultados digitados por um aluno em um teste:

 def printScores(student, *scores):   print(f"Student Name: {student}")   for score in scores:      print(score) printScores("Jonathan",100, 95, 88, 92, 99) """ Student Name: Jonathan 100 95 88 92 99 """ 

Eu não usei a construção *args ao declarar uma função. Em vez disso, tenho *scores . Há algum erro aqui? Não há erro aqui. O fato é que "args" é apenas um conjunto de caracteres usados ​​para denotar argumentos. A coisa mais importante aqui é o operador * . E o que exatamente vem depois, não desempenha um papel especial. Usando * criamos uma lista de argumentos posicionais com base no que foi passado para a função quando ela foi chamada.

Depois de descobrirmos *args , não haverá mais problemas com o entendimento dos **kwargs . O nome, novamente, não importa. O principal é dois caracteres ** . Graças a eles, é criado um dicionário que contém argumentos nomeados passados ​​para a função quando é chamada.

 def printPetNames(owner, **pets):   print(f"Owner Name: {owner}")   for pet,name in pets.items():      print(f"{pet}: {name}") printPetNames("Jonathan", dog="Brock", fish=["Larry", "Curly", "Moe"], turtle="Shelldon") """ Owner Name: Jonathan dog: Brock fish: ['Larry', 'Curly', 'Moe'] turtle: Shelldon """ 

Sumário


Aqui estão algumas dicas para ajudá-lo a evitar problemas comuns que surgem ao trabalhar com funções e expandir seu conhecimento:

  • Use as construções *args e **kwargs comuns para capturar argumentos posicionais e nomeados.
  • **kwarg s não pode ser colocado antes de *args . Se você fizer isso, uma mensagem de erro será exibida.
  • Cuidado com conflitos entre parâmetros nomeados e **kwargs , nos casos em que está planejado passar o valor como argumento **kwarg , mas o nome da chave desse valor corresponde ao nome do parâmetro nomeado.
  • O operador * pode ser usado não apenas nas declarações de função, mas também quando elas são chamadas.

Caros leitores! Quais parâmetros você costuma usar ao declarar funções do Python?

Source: https://habr.com/ru/post/pt482464/


All Articles