Argumentos normales frente a argumentos de palabras clave

289

¿En qué se diferencian los "argumentos de palabras clave" de los argumentos regulares? ¿No se pueden pasar todos los argumentos en name=valuelugar de utilizar la sintaxis posicional?

mk12
fuente
66
Es posible que también desee leer PEP 3102: están ordenando algunas de estas cosas en Python 3. Ver: python.org/dev/peps/pep-3102
Ben Hoyt
Y si hay o no un valor predeterminado no tiene nada que ver con eso (excepto si necesita o no pasarle un valor), ¿verdad?
mk12
@Ben Hoyt Agregó una respuesta a continuación que cubre Python 3, argumentos de palabras clave requeridas
Christophe Roussy

Respuestas:

346

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 cualquier parámetro que no se mencionó en absoluto.

El otro concepto está en el lado de la definición de funciones: puede definir una función que tome parámetros por nombre, y ni siquiera tiene que especificar cuáles son esos nombres. Estos son argumentos de palabras clave puras y no se pueden pasar posicionalmente. La sintaxis 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'}
Ian Clelland
fuente
55
+1 y aceptado: Eres el único que habló sobre ambos tipos de argumentos de palabras clave + posicionales, todos los demás pensaron que estaba hablando sobre el primero o el segundo (pero todavía eran buenas publicaciones). ¡Gracias!
mk12
34
La redacción no está clara: normalmente se habla de argumentos en el lado de la llamada, mientras que de los parámetros en el lado de la llamada.
glglgl
3
¿El nombre del parámetro tiene que ser kwargso puedo cambiarle el nombre a algo? como options( def my_fuction(arg1, arg2, **options))?
Bruce Sun
1
El nombre puede ser cualquier cosa, aunque kwargses la convención cuando no hay un nombre más apropiado
Matt Zimmerman
Creo que el segundo concepto explicado aquí se denomina técnicamente Argumentos de palabras clave arbitrarias.
Anshul Dahiya
188

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 *positionalargumento almacenará todos los argumentos posicionales pasados foo(), sin límite de cuántos puede proporcionar.

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

El **keywordsargumento almacenará cualquier argumento de palabra clave:

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

Y, por supuesto, puede 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 usan, pero ocasionalmente son muy útiles, y es importante saber qué argumentos son posicionales o palabras clave.

demasiado php
fuente
3
Excelente respuesta! Solo una nota de que los argumentos posicionales requeridos se pueden pasar antes *positionaly **keywordssi cambiamos la definición de la función como def foo(arg1, *positional, **keywords):. Aquí arg1es posicional y requerido. Tenga en cuenta que posicional en respuesta significa un número opcional y variable de argumentos posicionales.
shaffooo
2
Si buena respuesta. Otra nota: si llama a su función foo(bar=True), puede obtener los valores utilizando el bar = keywords.pop('bar')mismo que bar = keywords.pop('bar', None). Para el valor predeterminado, usebar = keywords.pop('bar', False)
olibre
111

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

def foo(bar, baz):
    pass

foo(1, 2)
foo(baz=2, bar=1)
Eli Gray
fuente
3
Gracias por esto. Es increíblemente útil que puedo tanto especificar una palabra clave arg arg como posicional, y un arg posicional como palabra clave arg.
Luke Davis el
47

Argumentos Posicionales

No tienen palabras clave antes que 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 descuida insertar las palabras clave, ¡entonces el orden será importante!

def func(foo=1, baz=2, hello=3): ...
func("bar", 5, 123)
Desconocido
fuente
8
En mi humilde opinión, el tercer ejemplo (argumentos predeterminados) no está claro. Creo que está hablando de lo que sucede cuando uno o más parámetros declaran valores predeterminados, y la llamada usa notación posicional, pero proporciona MENOS que el número de parámetros declarados. Sin embargo, su ejemplo tiene 3 declarados y 3 en la llamada, por lo que los valores predeterminados no tienen ningún efecto. ¿Pretendías omitir el 3er argumento? por ejemplo func("bar", 5)? Y luego decir que helloobtiene su valor predeterminado de 3.
ToolmakerSteve
25

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

  1. Por puesto. 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 usted tiene la opción de utilizar argumentos posicionales.

Si usted no utiliza argumentos posicionales, a continuación, - sí - todo lo que escribiste resulta ser un argumento de palabra clave.

Cuando se llama a una función de tomar una decisión de posición de uso o una 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.

S.Lott
fuente
1
Ohh, estaba pensando en los parámetros, cuando lo que en realidad son los argumentos (lo que paso). ¡Gracias!
mk12
24

Me sorprende que nadie parezca haber señalado que se puede pasar un diccionario de parámetros de argumentos clave, que satisfacen los parámetros formales, de esa manera.

>>> 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
>>> 
Sherman
fuente
11
+1 para una técnica útil. Su punto sería más claro, sin , **kwargs. Eso demostraría que incluso una simple función def, con un número fijo de parámetros, se puede suministrar un diccionario. Es decir, no requiere nada elegante en la definición. ENTONCES puede agregar un segundo ejemplo, CON ** kwargs en definición, y mostrar cómo los elementos EXTRA en el diccionario están disponibles a través de eso.
ToolmakerSteve
1
He visto que esto sucede en el código fuente de varias bibliotecas y estaba muy confundido. ¡Gracias por aclararme!
Craig Labenz
3
El cuarto parámetro formal anterior - ** kwargs es necesario si alguna vez llama a func con un diccionario que contiene claves distintas de 'a', 'b' y 'c'.
Eduardo
Para mí print 'a:%s, b:%s, c:%s' % (a, b, c)da error de sintaxis, sin embargo print('a:%s, b:%s, c:%s' % (a, b, c))funciona. ¿Algo con la versión de Python? De todos modos, gracias por esta idea, hasta ahora estaba usando el más torpeprint('a:{}, b:{}, c:{}'.format(a, b, c))
Axel Bregnsbo
17

Con Python 3 puede tener argumentos de palabras clave tanto obligatorios como no obligatorios :


Opcional : (valor predeterminado definido para el parámetro 'b')

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

Obligatorio (sin valor predeterminado definido para el parámetro '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 casos en los que tiene muchos argumentos similares uno al lado del otro, especialmente si son del mismo tipo, en ese caso prefiero usar argumentos con nombre o creo una clase personalizada si los argumentos van de la mano.

Christophe Roussy
fuente
3
La variante requerida es bastante útil. Insta a dar a los argumentos por nombre sin proporcionar valores predeterminados, lo que a menudo no tiene sentido.
TNT
Los valores predeterminados se ven bien y pueden ayudarlo a ahorrar tiempo cuando comienza, pero a la larga los valores predeterminados pueden ser un PITA.
Christophe Roussy
11

Me sorprende que nadie haya mencionado el hecho de que puede mezclar argumentos posicionales y de palabras clave para hacer cosas furtivas como esta usando *argsy **kwargs( desde 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 arbitrarias que pueden tener claves que no desea definir por adelantado.

Gabriel Hurley
fuente
0

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'))
A B okay {}
>>> d = {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', c='c', b='b', **d))
a b c {'f': 'F', 'g': 'G'}
>>> print(test_var_kwarg('a', 'b', 'c'))
a b c {}
jmunsch
fuente
0

Simplemente suplemente / agregue una forma de definir el valor predeterminado de los argumentos que no se asignan en palabras clave al llamar a la función:

def func(**keywargs):
if 'my_word' not in keywargs:
    word = 'default_msg'
else:
    word = keywargs['my_word']
return word

llama a esto por:

print(func())
print(func(my_word='love'))

obtendrás:

default_msg
love

Lea más sobre *argsy **kwargsen Python: https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3

sonictl
fuente