passe o argumento ** kwargs para outra função com ** kwargs


152

Eu não entendo o exemplo a seguir, digamos que eu tenho essas funções:

# python likes
def save(filename, data, **kwargs):
    fo = openX(filename, "w", **kwargs) # <- #1
    fo.write(data)
    fo.close()
# python doesnt like
def save2(filename, data, **kwargs):
    fo = openX(filename, "w", kwargs) # <- #2
    fo.write(data)
    fo.close()

def openX(filename, mode, **kwargs):
    #doing something fancy and returning a file object

Por que o número 1 é a solução certa e o número 2 é o errado? **kwargsé basicamente um ditado, então, se eu quiser passar o argumento para o openX, acho que o caminho correto seria sem **e apenas dando o ditado. Mas o python obviamente não gosta do segundo e me diz que dei 3 em vez de 2 argumentos. Então, qual é a razão por trás disso?

python 

5
Eu me pergunto por que você chama isso **argsno código. Este é possivelmente o pior nome possível, como as pessoas vão confundi-lo com*args
John La Rooy

1
Bem, eu realmente nunca uso * args, então uso ** args ^^, mas também posso modificá-lo.

Respostas:


155

No segundo exemplo, você fornece três argumentos: nome do arquivo, modo e um dicionário ( kwargs). Mas o Python espera: 2 argumentos formais mais argumentos de palavras-chave.

Ao prefixar o dicionário com '**', você descompacta o dicionário kwargsnos argumentos das palavras-chave.

Um dicionário (tipo dict) é uma única variável que contém pares de valores-chave.

"Argumentos de palavras-chave" são parâmetros-método de valor-chave.

Qualquer dicionário pode ser descompactado para argumentos de palavras-chave, prefixando-o **durante a chamada de função.


5
agora eu entendi. Eu pensei que palavras-chave e ditado eram a mesma coisa.

13
"Qualquer dicionário pode ser expandido para palavras-chave, prefixando-o com ** durante a chamada de função." <: isso é legal #


8
Um exemplo de código real tornaria essa resposta consideravelmente mais clara.
OrangeDog

12

A **sintaxe diz ao Python para coletar argumentos de palavras-chave em um dicionário. O save2está passando como um argumento que não é de palavra-chave (um objeto de dicionário). O openXnão está vendo nenhum argumento de palavra-chave para que **argsele não seja usado. Em vez disso, está obtendo um terceiro argumento que não é de palavra-chave (o dicionário). Para corrigir isso, mude a definição da openXfunção.

def openX(filename, mode, kwargs):
    pass

Obrigado, mas também quero usar o openX sem salvar, por isso tenho que ficar com as palavras-chave. Pensei passando para baixo palavras-chave foi basicamente o mesmo que passar por um dict, mas eu não sabia até agora :)

@xMRW Eles não podem ser a mesma coisa, pois você também pode passar um dicionário como parâmetro para qualquer função. Seu # 1 é o caminho certo então.
Keith

8

Expandindo a resposta da @gecco, a seguir está um exemplo que mostra a diferença:

def foo(**kwargs):
    for entry in kwargs.items():
        print("Key: {}, value: {}".format(entry[0], entry[1]))

# call using normal keys:
foo(a=1, b=2, c=3)
# call using an unpacked dictionary:
foo(**{"a": 1, "b":2, "c":3})

# call using a dictionary fails because the function will think you are
# giving it a positional argument
foo({"a": 1, "b": 2, "c": 3})
# this yields the same error as any other positional argument
foo(3)
foo("string")

Aqui você pode ver como a descompactação de um dicionário funciona e por que o envio de um dicionário real falha


1

Porque um dicionário é um valor único. Você precisará usar a expansão de palavras-chave se quiser passar como um grupo de argumentos de palavras-chave.


Desculpe, mas o que é uma "expansão de palavra-chave"? quer dizer que eu deveria usar dict_var em vez de ** args e apenas usando def func (argumento, dict_var = 0) ... func (1, {1: "a", 2: "b"})

1

Para o número 2, args será apenas um parâmetro formal com valor dict, mas não um parâmetro de tipo de palavra-chave.

Se você deseja passar um parâmetro de tipo de palavra-chave para um argumento de palavra-chave, é necessário especificar ** antes do seu dicionário, o que significa ** args

verifique isso para obter mais detalhes sobre o uso de ** kw

http://www.saltycrane.com/blog/2008/01/how-to-use-args-and-kwargs-in-python/


Então existe uma grande diferença entre ** kwargs e dict?

obrigado, eu sempre gosto de ler mais sobre tópicos que não entendo.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.