Astérisque nu dans les arguments de fonction?

242

Que fait un astérisque nu dans les arguments d'une fonction?

Quand j'ai regardé le module de cornichon , je vois ceci:

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

Je connais un astérisque simple et double précédant les arguments (pour un nombre variable d'arguments), mais cela ne précède rien. Et je suis presque sûr que cela n'a rien à voir avec les cornichons. Ce n'est probablement qu'un exemple de cela. Je n'ai appris son nom qu'en envoyant ceci à l'interprète:

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

Si cela importe, je suis sur python 3.3.0.

Eric
la source

Réponses:

221

Bare *est utilisé pour forcer l'appelant à utiliser des arguments nommés - vous ne pouvez donc pas définir une fonction avec *comme argument lorsque vous n'avez aucun argument de mot clé suivant.

Consultez cette réponse ou la documentation Python 3 pour plus de détails.

Kimvais
la source
3
Notez que tous les arguments positionnels (sans nom), y compris *args, doivent se produire avant le bare *.
BallpointBen
4
Notez également qu'il existe une sorte d'homologue, /, qui marque la fin des arguments de position uniquement ( stackoverflow.com/questions/28243832/… ).
Stephen
2
@BallpointBen: *est à la place de *args, et vice-versa; ils ne peuvent pas coexister dans une signature. C'est pourquoi ils ont choisi *; auparavant, *argsc'était le seul moyen de forcer des arguments purement positionnels, et cela marquait la fin des arguments qui pouvaient être passés positionnellement (car il collectait tous les arguments positionnels restants, ils pouvaient atteindre les arguments nommés suivants). *signifie les mêmes "arguments positionnels ne peuvent pas aller plus loin ici", mais l'absence de nom signifie "mais je ne les accepterai pas du tout, parce que j'ai choisi de ne pas fournir un endroit pour les mettre".
ShadowRanger
70

Alors que la réponse d'origine répond complètement à la question, il suffit d'ajouter un peu d'informations connexes. Le comportement de l'astérisque unique dérive de PEP-3102. Citant la section connexe:

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 anglais simple, cela signifie que pour transmettre la valeur de la clé, vous devrez la transmettre explicitement sous la forme key="value".

mu 無
la source
Oh, cela rend les choses beaucoup plus claires. Donc, avoir un argument * est comme avoir un argument args *, mais comme vous ne l'avez rien nommé, son seul effet est probablement de gober tranquillement tous les arguments positionnels restants, afin de forcer les autres arguments à être des mots clés -seulement.
Stephen
11
@Stephen I pensait aussi à l'origine, l'effet de bare *est d'avaler les arguments positionnels restants, mais ce n'est pas le cas. Le passage d'arguments positionnels supplémentaires que la fonction attend, donne une erreur de ce type: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

l'exemple ci-dessus avec ** kwargs

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

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

Sémantiquement, cela signifie que les arguments qui le suivent sont uniquement des mots clés, vous obtiendrez donc une erreur si vous essayez de fournir un argument sans spécifier son nom. Par exemple:

>>> 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

De manière pragmatique, cela signifie que vous devez appeler la fonction avec un argument mot-clé. Cela se fait généralement lorsqu'il est difficile de comprendre le but de l'argument sans l'indication donnée par le nom de l'argument.

Comparez par exemple sorted(nums, reverse=True)vs si vous avez écrit sorted(nums, True). Ce dernier serait beaucoup moins lisible, donc les développeurs Python ont choisi de vous faire l'écrire à l'ancienne.

kaya3
la source
4

Supposons que vous ayez une fonction:

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

Vous pouvez appeler cette fonction de 2 manières:

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

Supposons que vous souhaitiez que la fonction sumsoit appelée uniquement à l'aide d'arguments de mots clés.

Vous ajoutez *à la liste des paramètres de fonction pour marquer la fin des arguments positionnels.

Donc fonction définie comme:

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

peut être appelé uniquement en utilisant sum(1,key=2)

rok
la source
-1

J'ai trouvé le lien suivant très utile pour expliquer *, *argset **kwargs:

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

Essentiellement, en plus des réponses ci-dessus, j'ai appris du site ci-dessus (crédit: https://pythontips.com/author/yasoob008/ ) ce qui suit:

Avec la fonction de démonstration définie ci-dessous, il y a deux exemples, un avec *argset un avec**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

*argsVous permet donc de créer dynamiquement une liste d'arguments qui seront pris dans l'ordre dans lequel ils sont alimentés, tandis que **kwargspeut permettre le passage d'arguments NAMED et peut être traité par NAME en conséquence (quel que soit l'ordre dans lequel ils sont alimentés) .

Le site continue, notant que l'ordre correct des arguments doit être:

some_func(fargs,*args,**kwargs)
lb_so
la source
2
Cette réponse n'a presque rien à voir avec la question. Il utilise même une version obsolète de python qui n'a pas cette fonctionnalité.
Antti Haapala