¿Asterisco desnudo en argumentos de función?

242

¿Qué hace un asterisco desnudo en los argumentos de una función?

Cuando miré el módulo de pickle , veo esto:

pickle.dump(obj, file, protocol=None, *, fix_imports=True)

Sé sobre un asterisco simple y doble que precede a los argumentos (para un número variable de argumentos), pero esto no precede a nada. Y estoy bastante seguro de que esto no tiene nada que ver con el pepinillo. Probablemente sea solo un ejemplo de que esto está sucediendo. Solo supe su nombre cuando envié esto al intérprete:

>>> def func(*):
...     pass
...
  File "<stdin>", line 1
SyntaxError: named arguments must follow bare *

Si importa, estoy en Python 3.3.0.

Eric
fuente

Respuestas:

221

Desnudo *se usa para obligar a la persona que llama a usar argumentos con nombre, por lo que no puede definir una función *como argumento cuando no tiene argumentos de palabras clave siguientes.

Vea esta respuesta o la documentación de Python 3 para más detalles.

Kimvais
fuente
3
Tenga en cuenta que todos los argumentos posicionales (sin nombre), incluidos *args, deben aparecer antes de lo básico *.
BallpointBen
44
También tenga en cuenta que hay una especie de contraparte, /, que marca el final de los argumentos solo posicionales ( stackoverflow.com/questions/28243832/… ).
Stephen
2
@BallpointBen: *está en lugar de *args, y viceversa; No pueden coexistir en una firma. Por eso eligieron *; anteriormente, *argsera la única forma de forzar argumentos puramente posicionales, y marcaba el final de los argumentos que podían pasarse posicionalmente (dado que reunía todos los argumentos posicionales restantes, podían llegar a los siguientes argumentos nombrados). *significa que los mismos "argumentos posicionales no pueden ir más allá de aquí", pero la falta de un nombre significa "pero no los aceptaré en absoluto, porque elegí no proporcionar un lugar para ponerlos".
ShadowRanger
70

Si bien la respuesta original responde la pregunta por completo, solo agrega un poco de información relacionada. El comportamiento del asterisco único deriva de PEP-3102. Citando la sección relacionada:

The second syntactical change is to allow the argument name to
be omitted for a varargs argument. The meaning of this is to
allow for keyword-only arguments for functions that would not
otherwise take a varargs argument:

    def compare(a, b, *, key=None):
        ...

En inglés simple, significa que para pasar el valor de la clave, deberá pasarlo explícitamente como key="value".

mu 無
fuente
Oh, eso aclara mucho las cosas. Por lo tanto, tener un argumento * es como tener un argumento args *, pero dado que no lo ha nombrado nada, su único efecto es probablemente engullir silenciosamente todos los argumentos posicionales restantes, para forzar que los argumentos restantes sean palabras clave -solamente.
Stephen
11
@Stephen Yo también pensé originalmente, el efecto de desnudo *es engullir los argumentos posicionales restantes, pero ese no es el caso. Al pasar argumentos posicionales adicionales de lo que la función espera, se produce un error de este tipo:foo() takes exactly 1 positional argument (2 given)
Ajay M
19
def func(*, a, b):
    print(a)
    print(b)

func("gg") # TypeError: func() takes 0 positional arguments but 1 was given
func(a="gg") # TypeError: func() missing 1 required keyword-only argument: 'b'
func(a="aa", b="bb", c="cc") # TypeError: func() got an unexpected keyword argument 'c'
func(a="aa", b="bb", "cc") # SyntaxError: positional argument follows keyword argument
func(a="aa", b="bb") # aa, bb

el ejemplo anterior con ** kwargs

def func(*, a, b, **kwargs):
    print(a)
    print(b)
    print(kwargs)

func(a="aa",b="bb", c="cc") # aa, bb, {'c': 'cc'}
laycat
fuente
6

Semánticamente, significa que los argumentos que siguen son solo palabras clave, por lo que obtendrá un error si intenta proporcionar un argumento sin especificar su nombre. Por ejemplo:

>>> def f(a, *, b):
...     return a + b
...
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 1 positional argument but 2 were given
>>> f(1, b=2)
3

Pragmáticamente, significa que debe llamar a la función con un argumento de palabra clave. Por lo general, se hace cuando sería difícil entender el propósito del argumento sin la pista dada por el nombre del argumento.

Compare, por ejemplo, sorted(nums, reverse=True)vs. si escribió sorted(nums, True). Esto último sería mucho menos legible, por lo que los desarrolladores de Python decidieron obligarlo a escribirlo de la manera anterior.

kaya3
fuente
4

Supongamos que tiene una función:

def sum(a,key=5):
    return a + key 

Puede llamar a esta función de 2 maneras:

sum(1,2) o sum(1,key=2)

Suponga que desea sumque se llame a la función solo con argumentos de palabras clave.

Se agrega *a la lista de parámetros de funciones para marcar el final de los argumentos posicionales.

Entonces función definida como:

def sum(a,*,key=5):
    return a + key 

puede ser llamado solo usando sum(1,key=2)

rok
fuente
-1

He encontrado el siguiente enlace a ser muy útil para explicar *, *argsy **kwargs:

https://pythontips.com/2013/08/04/args-and-kwargs-in-python-explained/

Esencialmente, además de las respuestas anteriores, he aprendido del sitio anterior (crédito: https://pythontips.com/author/yasoob008/ ) lo siguiente:

Con la función de demostración definida primero a continuación, hay dos ejemplos, uno con *argsy otro con**kwargs

def test_args_kwargs(arg1, arg2, arg3):
    print "arg1:", arg1
    print "arg2:", arg2
    print "arg3:", arg3

# first with *args
>>> args = ("two", 3,5)
>>> test_args_kwargs(*args)
arg1: two
arg2: 3
arg3: 5

# now with **kwargs:
>>> kwargs = {"arg3": 3, "arg2": "two","arg1":5}
>>> test_args_kwargs(**kwargs)
arg1: 5
arg2: two
arg3: 3

Por lo tanto, le *argspermite construir dinámicamente una lista de argumentos que se tomarán en el orden en que se alimentan, mientras que **kwargspuede permitir el paso de argumentos NAMED y NAME puede procesarlos en consecuencia (independientemente del orden en que se alimentan) .

El sitio continúa, señalando que el orden correcto de los argumentos debe ser:

some_func(fargs,*args,**kwargs)
lb_so
fuente
2
Esta respuesta no tiene casi nada que ver con la pregunta. Incluso está utilizando una versión obsoleta de Python que no tiene la función.
Antti Haapala