Qual é a maneira correta de usar **kwargs
no Python quando se trata de valores padrão?
kwargs
retorna um dicionário, mas qual é a melhor maneira de definir valores padrão ou existe um? Devo acessá-lo como um dicionário? Use a função get?
class ExampleClass:
def __init__(self, **kwargs):
self.val = kwargs['val']
self.val2 = kwargs.get('val2')
Uma pergunta simples, mas na qual não consigo encontrar bons recursos. As pessoas fazem isso de maneiras diferentes no código que eu já vi e é difícil saber o que usar.
__init__()
. Alguém pode explicar por que essa é uma transgressão digna de fiapos?self.__dict__update(**kwargs)
pode redefinir métodos e causar outros errosEmbora a maioria das respostas esteja dizendo que, por exemplo,
é o mesmo que"
isso não é verdade. No último caso,
f
pode ser chamado comof(23, 42)
, enquanto o primeiro caso aceita apenas argumentos nomeados - sem chamadas posicionais. Freqüentemente, você deseja permitir ao chamador a máxima flexibilidade e, portanto, a segunda forma, como a maioria das respostas afirma, é preferível: mas esse nem sempre é o caso. Quando você aceita muitos parâmetros opcionais dos quais normalmente apenas alguns são passados, pode ser uma excelente idéia (evitar acidentes e códigos ilegíveis nos sites de chamadas!) Forçar o uso de argumentos nomeados -threading.Thread
é um exemplo. A primeira forma é como você implementa isso no Python 2.O idioma é tão importante que, no Python 3, agora ele possui uma sintaxe de suporte especial: todos os argumentos após um único
*
nadef
assinatura são apenas de palavras-chave, ou seja, não podem ser passados como argumentos posicionais, mas apenas como nomeados. Portanto, no Python 3, você pode codificar o código acima como:De fato, no Python 3 você pode até ter argumentos apenas de palavras-chave que não são opcionais (sem valor padrão).
No entanto, o Python 2 ainda tem longos anos de vida produtiva pela frente, por isso é melhor não esquecer as técnicas e expressões que permitem implementar no Python 2 importantes idéias de design que são diretamente suportadas na linguagem do Python 3!
fonte
Sugiro algo parecido com isto
E então use os valores da maneira que quiser
dictionaryA.update(dictionaryB)
adiciona o conteúdodictionaryB
dadictionaryA
substituir quaisquer chaves duplicadas.fonte
for key in options: self.__setattr__(key, options[key])
e estou pronto para ir. :)Você faria
ou
Se você usar
pop
, poderá verificar se há algum valor falso enviado e tomar a ação apropriada (se houver).fonte
.pop
ajudá-lo a "verificar se há algum valor falso enviado"?kwargs
por um motivo.default_value
passado? E remove essa chave depois?Usar ** kwargs e valores padrão é fácil. Às vezes, no entanto, você não deve usar ** kwargs em primeiro lugar.
Nesse caso, não estamos realmente fazendo o melhor uso de ** kwargs.
O acima é um "por que se preocupar?" declaração. É o mesmo que
Quando você usa ** kwargs, significa que uma palavra-chave não é apenas opcional, mas condicional. Existem regras mais complexas do que valores padrão simples.
Quando você usa ** kwargs, geralmente significa algo mais como o seguinte, onde padrões simples não se aplicam.
fonte
Como
**kwargs
é usado quando o número de argumentos é desconhecido, por que não fazer isso?fonte
Aqui está outra abordagem:
fonte
get_form_kwargs()
). Você podeget_form()
método mostra como obter argumentos de palavras-chave extensivamente, adiando para outro método (get_form_kwargs
como mencionado acima). Ele instancia o formulário da seguinte forma:form_class(**self.get_form_kwargs())
.get_form_kwargs()
em uma visualização de subclasse e adicionar / remover kwargs com base em lógica específica. Mas isso é para um tutorial do Django.Eu acho que a maneira correta de usar
**kwargs
em Python quando se trata de valores padrão é usar o método de dicionáriosetdefault
, conforme indicado abaixo:Dessa forma, se um usuário passar 'val' ou 'val2' na palavra-chave
args
, eles serão usados; caso contrário, os valores padrão que foram definidos serão usados.fonte
Você poderia fazer algo assim
fonte
Dando seguimento a @srhegde sugestão de usar setattr :
Essa variante é útil quando se espera que a classe tenha todos os itens de nossa
acceptable
lista.fonte
Se você quiser combinar isso com * args, precisará manter * args e ** kwargs no final da definição.
Assim:
fonte
@AbhinavGupta e @Steef sugeriram o uso
update()
, que achei muito útil para processar grandes listas de argumentos:E se quisermos verificar se o usuário não passou nenhum argumento espúrio / sem suporte? O @VinaySajip apontou que
pop()
pode ser usado para processar iterativamente a lista de argumentos. Então, quaisquer argumentos restantes são espúrios. Agradável.Aqui está outra maneira possível de fazer isso, que mantém a sintaxe simples de usar
update()
:unknown_args
é umset
contendo os nomes dos argumentos que não ocorrem nos padrões.fonte
Outra solução simples para o processamento de argumentos desconhecidos ou múltiplos pode ser:
fonte
** kwargs oferece a liberdade de adicionar qualquer número de argumentos de palavras-chave. Pode-se ter uma lista de chaves para as quais ele pode definir valores padrão. Mas definir valores padrão para um número indefinido de chaves parece desnecessário. Finalmente, pode ser importante ter as chaves como atributos da instância. Então, eu faria o seguinte:
fonte