Qual é o objetivo e o uso de ** kwargs?

763

Quais são os usos para **kwargs Python?

Eu sei que você pode fazer uma objects.filtersobre uma mesa e passar uma **kwargsdiscussão.  

Também posso fazer isso para especificar deltas de tempo, ou seja timedelta(hours = time1)?

Como exatamente isso funciona? É classes como 'descompactar'? Gosta a,b=1,2?

Federer
fonte
27
Se você se deparar com essa pergunta como eu, veja também: * args e ** kwargs?
sumid 16/02/2012
3
Uma explicação notavelmente concisa aqui : "* coleta todos os argumentos posicionais em uma tupla", "** coleta todos os argumentos de palavras-chave em um dicionário". A palavra-chave é coletada .
Osa
24
Apenas FYI: kwargssignifica KeyWord ARGumentS, ou seja, os argumentos que estabeleceram chaves
Richard de Wit

Respostas:

868

Você pode usar **kwargspara permitir que suas funções recebam um número arbitrário de argumentos de palavras-chave ("kwargs" significa "argumentos de palavras-chave"):

>>> def print_keyword_args(**kwargs):
...     # kwargs is a dict of the keyword args passed to the function
...     for key, value in kwargs.iteritems():
...         print "%s = %s" % (key, value)
... 
>>> print_keyword_args(first_name="John", last_name="Doe")
first_name = John
last_name = Doe

Você também pode usar a **kwargssintaxe ao chamar funções, construindo um dicionário de argumentos de palavras-chave e passando-o para sua função:

>>> kwargs = {'first_name': 'Bobby', 'last_name': 'Smith'}
>>> print_keyword_args(**kwargs)
first_name = Bobby
last_name = Smith

O Tutorial do Python contém uma boa explicação de como funciona, além de alguns bons exemplos.

<--Atualização-->

Para pessoas que usam Python 3, em vez de iteritems (), use items ()

Pär Wieslander
fonte
1
@ yashas123 Não; se você fizer um loop sobre algo vazio, nada acontecerá; portanto, qualquer código que possa vir a seguir será executado normalmente.
JG
330

Descompactando dicionários

** descompacta dicionários.

este

func(a=1, b=2, c=3)

é o mesmo que

args = {'a': 1, 'b': 2, 'c':3}
func(**args)

É útil se você precisar construir parâmetros:

args = {'name': person.name}
if hasattr(person, "address"):
    args["address"] = person.address
func(**args)  # either expanded to func(name=person.name) or
              #                    func(name=person.name, address=person.address)

Parâmetros de embalagem de uma função

def setstyle(**styles):
    for key, value in styles.iteritems():      # styles is a regular dictionary
        setattr(someobject, key, value)

Isso permite que você use a função assim:

setstyle(color="red", bold=False)
Georg Schölly
fonte
13
kwarg é apenas um nome de variável, certo? para que eu possa usar def func (** args): e funcionou?
Sriram
11
@Sriram: Certo. Os asteriscos são importantes. kwargs é apenas o nome que se dá se não houver melhor. (Normalmente existe.)
Georg Schölly
54
@Sriram: para facilitar a leitura, você deve se ater ao kwargs - outros programadores irão apreciá-lo.
Johndodo 21/03
12
** do unpack dictionaries.>> mente soprada / é claro! +1 por explicar esse bit.
Marc
13
Nota: .iteritems()foi renomeado para .items()no Python 3.
fnkr
67

O kwargs é apenas um dicionário que é adicionado aos parâmetros.

Um dicionário pode conter pares de chave e valor. E esses são os kwargs. Ok, é assim.

O para quê não é tão simples.

Por exemplo (muito hipotético), você tem uma interface que apenas chama outras rotinas para fazer o trabalho:

def myDo(what, where, why):
   if what == 'swim':
      doSwim(where, why)
   elif what == 'walk':
      doWalk(where, why)
   ...

Agora você obtém um novo método "drive":

elif what == 'drive':
   doDrive(where, why, vehicle)

Mas espere um minuto, há um novo parâmetro "veículo" - você não sabia disso antes. Agora você deve adicioná-lo à assinatura da função myDo.

Aqui você pode jogar kwargs em jogo - basta adicionar kwargs à assinatura:

def myDo(what, where, why, **kwargs):
   if what == 'drive':
      doDrive(where, why, **kwargs)
   elif what == 'swim':
      doSwim(where, why, **kwargs)

Dessa forma, você não precisa alterar a assinatura da função da interface toda vez que algumas de suas rotinas chamadas podem mudar.

Este é apenas um bom exemplo que você pode considerar útil.

Juergen
fonte
46

Com base em que uma boa amostra às vezes é melhor que um longo discurso, escreverei duas funções usando todas as facilidades de passagem de argumentos das variáveis ​​python (argumentos posicionais e nomeados). Você deve poder ver facilmente o que faz sozinho:

def f(a = 0, *args, **kwargs):
    print("Received by f(a, *args, **kwargs)")
    print("=> f(a=%s, args=%s, kwargs=%s" % (a, args, kwargs))
    print("Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)")
    g(10, 11, 12, *args, d = 13, e = 14, **kwargs)

def g(f, g = 0, *args, **kwargs):
    print("Received by g(f, g = 0, *args, **kwargs)")
    print("=> g(f=%s, g=%s, args=%s, kwargs=%s)" % (f, g, args, kwargs))

print("Calling f(1, 2, 3, 4, b = 5, c = 6)")
f(1, 2, 3, 4, b = 5, c = 6)

E aqui está a saída:

Calling f(1, 2, 3, 4, b = 5, c = 6)
Received by f(a, *args, **kwargs) 
=> f(a=1, args=(2, 3, 4), kwargs={'c': 6, 'b': 5}
Calling g(10, 11, 12, *args, d = 13, e = 14, **kwargs)
Received by g(f, g = 0, *args, **kwargs)
=> g(f=10, g=11, args=(12, 2, 3, 4), kwargs={'c': 6, 'b': 5, 'e': 14, 'd': 13})
kriss
fonte
28

Motivo: *argse **kwargsserve como um espaço reservado para os argumentos que precisam ser passados ​​para uma chamada de função

usando *argse **kwargspara chamar uma função

def args_kwargs_test(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

Agora usaremos *argspara chamar a função definida acima

#args can either be a "list" or "tuple"
>>> args = ("two", 3, 5)  
>>> args_kwargs_test(*args)

resultado:

arg1: dois
arg2: 3
arg3: 5


Agora, usando **kwargspara chamar a mesma função

#keyword argument "kwargs" has to be a dictionary
>>> kwargs = {"arg3":3, "arg2":'two', "arg1":5}
>>> args_kwargs_test(**kwargs)

resultado:

arg1: 5
arg2: dois
arg3: 3

Bottomline: *argsnão tem inteligência, ele simplesmente interpola os argumentos passados ​​para os parâmetros (na ordem da esquerda para a direita) enquanto **kwargsse comporta de maneira inteligente, colocando o valor apropriado no local necessário

kmario23
fonte
24
  • kwargsin **kwargsé apenas o nome da variável. Você pode muito bem ter**anyVariableName
  • kwargssignifica "argumentos da palavra-chave". Mas eu acho que eles deveriam ser chamados de "argumentos nomeados", pois esses são simplesmente argumentos passados ​​junto com nomes (não encontro significado para a palavra "palavra-chave" no termo "argumentos da palavra-chave". Acho que "palavra-chave" geralmente significa palavras reservadas pela linguagem de programação e, portanto, não devem ser usadas pelo programador para nomes de variáveis. Isso não está acontecendo aqui no caso de kwargs.). Por isso, damos nomes param1e param2para dois valores de parâmetros passados para a função da seguinte forma: func(param1="val1",param2="val2"), em vez de passar apenas valores: func(val1,val2). Portanto, acho que eles devem ser chamados apropriadamente "número arbitrário de argumentos nomeados", pois podemos especificar qualquer número desses parâmetros (ou seja,funcfunc(**kwargs)

Sendo assim, deixe-me explicar primeiro "argumentos nomeados" e depois "número arbitrário de argumentos nomeados" kwargs.

Argumentos nomeados

  • args nomeados devem seguir argumentos posicionais
  • ordem dos argumentos nomeados não é importante
  • Exemplo

    def function1(param1,param2="arg2",param3="arg3"):
        print("\n"+str(param1)+" "+str(param2)+" "+str(param3)+"\n")
    
    function1(1)                      #1 arg2 arg3   #1 positional arg
    function1(param1=1)               #1 arg2 arg3   #1 named arg
    function1(1,param2=2)             #1 2 arg3      #1 positional arg, 1 named arg
    function1(param1=1,param2=2)      #1 2 arg3      #2 named args       
    function1(param2=2, param1=1)     #1 2 arg3      #2 named args out of order
    function1(1, param3=3, param2=2)  #1 2 3         #
    
    #function1()                      #invalid: required argument missing
    #function1(param2=2,1)            #invalid: SyntaxError: non-keyword arg after keyword arg
    #function1(1,param1=11)           #invalid: TypeError: function1() got multiple values for argument 'param1'
    #function1(param4=4)              #invalid: TypeError: function1() got an unexpected keyword argument 'param4'

Número arbitrário de argumentos nomeados kwargs

  • Sequência de parâmetros de função:
    1. parâmetros posicionais
    2. parâmetro formal que captura um número arbitrário de argumentos (prefixado com *)
    3. parâmetros formais nomeados
    4. parâmetro formal que captura um número arbitrário de parâmetros nomeados (prefixado com **)
  • Exemplo

    def function2(param1, *tupleParams, param2, param3, **dictionaryParams):
        print("param1: "+ param1)
        print("param2: "+ param2)
        print("param3: "+ param3)
        print("custom tuple params","-"*10)
        for p in tupleParams:
            print(str(p) + ",")
        print("custom named params","-"*10)
        for k,v in dictionaryParams.items():
            print(str(k)+":"+str(v))
    
    function2("arg1",
              "custom param1",
              "custom param2",
              "custom param3",
              param3="arg3",
              param2="arg2", 
              customNamedParam1 = "val1",
              customNamedParam2 = "val2"
              )
    
    # Output
    #
    #param1: arg1
    #param2: arg2
    #param3: arg3
    #custom tuple params ----------
    #custom param1,
    #custom param2,
    #custom param3,
    #custom named params ----------
    #customNamedParam2:val2
    #customNamedParam1:val1

Passando variáveis ​​tuplas e dict para argumentos personalizados

Para finalizar, deixe-me notar também que podemos passar

  • "parâmetro formal que captura um número arbitrário de argumentos" como variável de tupla e
  • "parâmetro formal que captura um número arbitrário de parâmetros nomeados" como variável dict

Assim, a mesma chamada acima pode ser feita da seguinte maneira:

tupleCustomArgs = ("custom param1", "custom param2", "custom param3")
dictCustomNamedArgs = {"customNamedParam1":"val1", "customNamedParam2":"val2"}

function2("arg1",
      *tupleCustomArgs,    #note *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs     #note **
      )

Finalmente, observe *e **nas chamadas de função acima. Se os omitirmos, podemos obter resultados ruins.

Omitindo *em tuplas args:

function2("arg1",
      tupleCustomArgs,   #omitting *
      param3="arg3",
      param2="arg2", 
      **dictCustomNamedArgs
      )

impressões

param1: arg1
param2: arg2
param3: arg3
custom tuple params ----------
('custom param1', 'custom param2', 'custom param3'),
custom named params ----------
customNamedParam2:val2
customNamedParam1:val1

A tupla acima ('custom param1', 'custom param2', 'custom param3')é impressa como está.

Omitindo dictargs:

function2("arg1",
      *tupleCustomArgs,   
      param3="arg3",
      param2="arg2", 
      dictCustomNamedArgs   #omitting **
      )

dictCustomNamedArgs
         ^
SyntaxError: non-keyword arg after keyword arg
Mahesha999
fonte
3
Eu imagino que a keywordterminologia vem do fato de você estar passando um ditado que é um banco de dados de pares de valores-chave.
Crobar
você quer dizer palavra "chave" em pares de valores "chave"? Também não é geralmente chamado de banco de dados, mas dicionário. Mas ainda não foi possível encontrar nenhum significado para o uso da palavra "palavra-chave".
Mahesha999
9

Além disso, você também pode misturar diferentes formas de uso ao chamar funções do kwargs:

def test(**kwargs):
    print kwargs['a']
    print kwargs['b']
    print kwargs['c']


args = { 'b': 2, 'c': 3}

test( a=1, **args )

dá esta saída:

1
2
3

Observe que ** kwargs deve ser o último argumento

philipp
fonte
5

kwargs é um açúcar sintático para passar argumentos de nome como dicionários (para func) ou dicionários como argumentos nomeados (para func)


fonte
5

Aqui está uma função simples que serve para explicar o uso:

def print_wrap(arg1, *args, **kwargs):
    print(arg1)
    print(args)
    print(kwargs)
    print(arg1, *args, **kwargs)

Quaisquer argumentos que não sejam especificados na definição da função serão colocados na argslista, ou na kwargslista, dependendo se são argumentos de palavra-chave ou não:

>>> print_wrap('one', 'two', 'three', end='blah', sep='--')
one
('two', 'three')
{'end': 'blah', 'sep': '--'}
one--two--threeblah

Se você adicionar um argumento de palavra-chave que nunca é passado para uma função, será gerado um erro:

>>> print_wrap('blah', dead_arg='anything')
TypeError: 'dead_arg' is an invalid keyword argument for this function
naught101
fonte
1

Aqui está um exemplo que eu espero que seja útil:

#! /usr/bin/env python
#
def g( **kwargs) :
  print ( "In g ready to print kwargs" )
  print kwargs
  print ( "in g, calling f")
  f ( **kwargs )
  print ( "In g, after returning from f")

def f( **kwargs ) :
  print ( "in f, printing kwargs")
  print ( kwargs )
  print ( "In f, after printing kwargs")


g( a="red", b=5, c="Nassau")

g( q="purple", w="W", c="Charlie", d=[4, 3, 6] )

Quando você executa o programa, obtém:

$ python kwargs_demo.py 
In g ready to print kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
in g, calling f
in f, printing kwargs
{'a': 'red', 'c': 'Nassau', 'b': 5}
In f, after printing kwargs
In g, after returning from f
In g ready to print kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
in g, calling f
in f, printing kwargs
{'q': 'purple', 'c': 'Charlie', 'd': [4, 3, 6], 'w': 'W'}
In f, after printing kwargs
In g, after returning from f

A chave aqui é que o número variável de argumentos nomeados na chamada se traduz em um dicionário na função.

user1928764
fonte
0

Este é o exemplo simples de entender sobre a descompactação do python ,

>>> def f(*args, **kwargs):
...    print 'args', args, 'kwargs', kwargs

eg1:

>>>f(1, 2)
>>> args (1,2) kwargs {} #args return parameter without reference as a tuple
>>>f(a = 1, b = 2)
>>> args () kwargs {'a': 1, 'b': 2} #args is empty tuple and kwargs return parameter with reference as a dictionary
Mohideen bin Mohammed
fonte
0

Em Java, você usa construtores para sobrecarregar classes e permitir vários parâmetros de entrada. No python, você pode usar o kwargs para fornecer um comportamento semelhante.

exemplo de java: https://beginnersbook.com/2013/05/constructor-overloading/

exemplo python:

class Robot():
    # name is an arg and color is a kwarg
    def __init__(self,name, color='red'):
        self.name = name
        self.color = color

red_robot = Robot('Bob')
blue_robot = Robot('Bob', color='blue')

print("I am a {color} robot named {name}.".format(color=red_robot.color, name=red_robot.name))
print("I am a {color} robot named {name}.".format(color=blue_robot.color, name=blue_robot.name))

>>> I am a red robot named Bob.
>>> I am a blue robot named Bob.

apenas outra maneira de pensar sobre isso.

Aidan Melen
fonte
0

Os argumentos de palavra- chave costumam ser reduzidos para kwargs em Python. Na programação de computadores ,

Os argumentos de palavra-chave referem-se ao suporte de uma linguagem de computador para chamadas de função que indicam claramente o nome de cada parâmetro na chamada de função.

O uso dos dois asterisco antes do nome do parâmetro, ** kwargs , é quando não se sabe quantos argumentos de palavras-chave serão passados ​​para a função. Nesse caso, chama-se Argumentos de palavra-chave arbitrária / curinga.

Um exemplo disso são as funções de receptor do Django .

def my_callback(sender, **kwargs):
    print("Request finished!")

Observe que a função aceita um argumento de remetente, juntamente com argumentos de palavra-chave curinga (** kwargs); todos os manipuladores de sinais devem aceitar esses argumentos. Todos os sinais enviam argumentos de palavras-chave e podem alterá-los a qualquer momento. No caso de request_finished , está documentado como não enviando argumentos, o que significa que podemos ser tentados a escrever nosso tratamento de sinal como my_callback (remetente).

Isso seria errado - na verdade, o Django lançará um erro se você fizer isso. Isso porque a qualquer momento os argumentos podem ser adicionados ao sinal e seu receptor deve ser capaz de lidar com esses novos argumentos.

Observe que ele não precisa ser chamado de kwargs , mas precisa ter ** (o nome kwargs é uma convenção).

Tiago Martins Peres
fonte