Argumentos normales vs. argumentos de palabras clave

¿En qué se diferencian los “argumentos de palabras clave” de los argumentos normales? ¿No se pueden pasar todos los argumentos como name=value lugar de usar la syntax posicional?

Hay dos conceptos relacionados, ambos llamados “argumentos de palabras clave”.

En el lado de la llamada, que es lo que han mencionado otros comentaristas, tiene la capacidad de especificar algunos argumentos de función por nombre. Debe mencionarlos después de todos los argumentos sin nombres (argumentos posicionales), y debe haber valores predeterminados para todos los parámetros que no se mencionaron en absoluto.

El otro concepto está en el lado de la definición de la función: puede definir una función que toma parámetros por nombre, y ni siquiera tiene que especificar cuáles son esos nombres. Estos son argumentos puros de palabras clave, y no se pueden pasar de manera posicional. La syntax es

 def my_function(arg1, arg2, **kwargs) 

Cualquier argumento de palabra clave que pase a esta función se colocará en un diccionario llamado kwargs. Puede examinar las claves de este diccionario en tiempo de ejecución, así:

 def my_function(**kwargs): print str(kwargs) my_function(a=12, b="abc") {'a': 12, 'b': 'abc'} 

Hay una última característica del idioma donde la distinción es importante. Considere la siguiente función:

 def foo(*positional, **keywords): print "Positional:", positional print "Keywords:", keywords 

El *positional argumento *positional almacenará todos los argumentos posicionales pasados ​​a foo() , sin límite de cuántos puede proporcionar.

 >>> foo('one', 'two', 'three') Positional: ('one', 'two', 'three') Keywords: {} 

El argumento de **keywords almacenará cualquier argumento de palabras clave:

 >>> foo(a='one', b='two', c='three') Positional: () Keywords: {'a': 'one', 'c': 'three', 'b': 'two'} 

Y, por supuesto, puedes usar ambos al mismo tiempo:

 >>> foo('one','two',c='three',d='four') Positional: ('one', 'two') Keywords: {'c': 'three', 'd': 'four'} 

Estas características rara vez se utilizan, pero en ocasiones son muy útiles, y es importante saber qué argumentos son posicionales o palabras clave.

Usar argumentos de palabras clave es lo mismo que argumentos normales, excepto que el orden no importa. Por ejemplo, las dos funciones de llamadas a continuación son las mismas:

 def foo(bar, baz): pass foo(1, 2) foo(baz=2, bar=1) 

Argumentos posicionales

No tienen palabras clave delante de ellos. ¡El orden es importante!

 func(1,2,3, "foo") 

Argumentos de palabras clave

Tienen palabras clave en el frente. ¡Pueden estar en cualquier orden!

 func(foo="bar", baz=5, hello=123) func(baz=5, foo="bar", hello=123) 

También debe saber que si usa argumentos predeterminados y no inserta las palabras clave, ¡entonces el orden será importante!

 def func(foo=1, baz=2, hello=3): ... func("bar", 5, 123) 

Hay dos formas de asignar valores de argumento a parámetros de función, ambos se utilizan.

  1. Por posición. Los argumentos posicionales no tienen palabras clave y se asignan primero.

  2. Por palabra clave. Los argumentos de palabras clave tienen palabras clave y se asignan en segundo lugar, después de los argumentos posicionales.

Tenga en cuenta que tiene la opción de usar argumentos posicionales.

Si no usa argumentos posicionales, entonces, sí, todo lo que escribió es un argumento de palabra clave.

Cuando llama a una función, toma la decisión de usar una posición o palabra clave o una mezcla. Puede elegir hacer todas las palabras clave si lo desea. Algunos de nosotros no hacemos esta elección y usamos argumentos posicionales.

Me sorprende que nadie parece haber señalado que se puede pasar un diccionario de parámetros de argumentos con clave, que satisfagan los parámetros formales, como tal.

 >>> def func(a='a', b='b', c='c', **kwargs): ... print 'a:%s, b:%s, c:%s' % (a, b, c) ... >>> func() a:a, b:b, c:c >>> func(**{'a' : 'z', 'b':'q', 'c':'v'}) a:z, b:q, c:v >>> 

Usando Python 3 puede tener argumentos de palabras clave requeridas y no requeridas:

Opcional : (valor predeterminado definido para ‘b’)

 def func1(a, *, b=42): ... func1(value_for_a) # b is optional and will default to 42 

Requerido (ningún valor predeterminado definido para ‘b’):

 def func2(a, *, b): ... func2(value_for_a, b=21) # b is set to 21 by the function call func2(value_for_a) # ERROR: missing 1 required keyword-only argument: 'b'` 

Esto puede ayudar en los casos en que tenga muchos argumentos similares uno al lado del otro, especialmente cuando sean del mismo tipo, en ese caso, prefiero usar argumentos con nombre o creo una clase personalizada si los argumentos pertenecen juntos.

Me sorprende que nadie haya mencionado el hecho de que puedes mezclar argumentos posicionales y de palabras clave para hacer cosas **kwargs como esta usando *args y **kwargs ( de este sitio ):

 def test_var_kwargs(farg, **kwargs): print "formal arg:", farg for key in kwargs: print "another keyword arg: %s: %s" % (key, kwargs[key]) 

Esto le permite utilizar argumentos de palabras clave arbitrarios que pueden tener claves que no desea definir por adelantado.

Estaba buscando un ejemplo que tuviera kwargs predeterminados usando la anotación de tipo:

 def test_var_kwarg(a: str, b: str='B', c: str='', **kwargs) -> str: return ' '.join([a, b, c, str(kwargs)]) 

ejemplo:

 >>> print(test_var_kwarg('A', c='okay')) AB okay {} >>> d = {'f': 'F', 'g': 'G'} >>> print(test_var_kwarg('a', c='c', b='b', **d)) abc {'f': 'F', 'g': 'G'} >>> print(test_var_kwarg('a', 'b', 'c')) abc {}