Embora a maioria das respostas esteja dizendo que, por exemplo,
def f(**kwargs):
foo = kwargs.pop('foo')
bar = kwargs.pop('bar')
...etc...
é o mesmo que"
def f(foo=None, bar=None, **kwargs):
...etc...
isso não é verdade. No último caso, f
pode ser chamado como f(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 *
na def
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:
def f(*, foo=None, bar=None, **kwargs):
...etc...
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!