Que font ** (double étoile / astérisque) et * (étoile / astérisque) pour les paramètres?

2353

Dans les définitions de méthode suivantes, à quoi servent les *et **quoi faire param2?

def foo(param1, *param2):
def bar(param1, **param2):
Todd
la source
4
voir aussi stackoverflow.com/questions/6967632/…
Aaron Hall
Voir aussi stackoverflow.com/questions/14301967/… pour un astérisque nu
naught101
24
Cette question est une cible en double très populaire, mais malheureusement, elle est souvent utilisée de manière incorrecte. Gardez à l'esprit que cette question concerne la définition de fonctions avec varargs ( def func(*args)). Pour une question demandant ce que cela signifie dans les appels de fonction ( func(*[1,2])), voir ici . Pour une question demandant comment décompresser les listes d'arguments, voir ici . Pour une question demandant ce que *signifient les littéraux ( [*[1, 2]]), voir ici .
Aran-Fey
Vous pouvez en apprendre plus sur son utilisation dans la définition de fonction et l'appel de fonction ici: pythontips.com/2013/08/04/args-and-kwargs-in-python-explained
Akshay Anurag

Réponses:

2239

Le *argset **kwargsest un idiome commun pour permettre un nombre arbitraire d'arguments aux fonctions comme décrit dans la section plus sur la définition des fonctions dans la documentation Python.

Le *argsvous donnera tous les paramètres de fonction sous forme de tuple :

def foo(*args):
    for a in args:
        print(a)        

foo(1)
# 1

foo(1,2,3)
# 1
# 2
# 3

Le **kwargsvous donnera tous les arguments de mot-clé, à l' exception de ceux correspondant à un paramètre formel en tant que dictionnaire.

def bar(**kwargs):
    for a in kwargs:
        print(a, kwargs[a])  

bar(name='one', age=27)
# age 27
# name one

Les deux idiomes peuvent être mélangés avec des arguments normaux pour autoriser un ensemble d'arguments fixes et certains arguments variables:

def foo(kind, *args, **kwargs):
   pass

Il est également possible de l'utiliser dans l'autre sens:

def foo(a, b, c):
    print(a, b, c)

obj = {'b':10, 'c':'lee'}

foo(100,**obj)
# 100 10 lee

Une autre utilisation de l' *lidiome est de décompresser les listes d'arguments lors de l'appel d'une fonction.

def foo(bar, lee):
    print(bar, lee)

l = [1,2]

foo(*l)
# 1 2

En Python 3, il est possible d'utiliser *lsur le côté gauche d'une affectation ( Extended Iterable Unpacking ), bien qu'il donne une liste au lieu d'un tuple dans ce contexte:

first, *rest = [1,2,3,4]
first, *l, last = [1,2,3,4]

Python 3 ajoute également une nouvelle sémantique (voir PEP 3102 ):

def func(arg1, arg2, arg3, *, kwarg1, kwarg2):
    pass

Cette fonction n'accepte que 3 arguments positionnels, et tout ce qui suit *ne peut être passé que comme arguments de mots clés.

Peter Hoffmann
la source
9
La sortie de [6] est dans l'ordre inverse.
Nommez
54
@ thanos.a Les dictés Python, utilisés sémantiquement pour le passage d'arguments de mots clés, sont arbitrairement ordonnés. Cependant, dans Python 3.6, les arguments de mots clés sont garantis pour se souvenir de l'ordre d'insertion. "L'ordre des éléments dans **kwargsmaintenant correspond à l'ordre dans lequel les arguments des mots clés ont été passés à la fonction." - docs.python.org/3/whatsnew/3.6.html En fait, tous les dicts dans CPython 3.6 se souviendront de l'ordre d'insertion comme détail d'implémentation, cela devient standard dans Python 3.7.
Aaron Hall
13
Très précis, propre et facile à comprendre. J'apprécie que vous ayez remarqué qu'il s'agit d'un "opérateur de déballage", afin que je puisse me différencier du passage par référence en C. +1
bballdave025
Comment tester la dernière fonction avec PEP 3102? Je l'appelle avec func (1,2,3, name = "me", age = 10) et il lève une exception:got an unexpected keyword argument 'name'
Kok How Teh
@KokHowTeh Vous devez passer les kwargs nommés tels qu'ils sont dans la fonction: func (1, 2, 3, kwarg1 = 'me', kwarg2 = 10)
John Aaron
622

Il convient également de noter que vous pouvez également utiliser *et **lorsque vous appelez des fonctions. Il s'agit d'un raccourci qui vous permet de passer plusieurs arguments à une fonction directement à l'aide d'une liste / tuple ou d'un dictionnaire. Par exemple, si vous avez la fonction suivante:

def foo(x,y,z):
    print("x=" + str(x))
    print("y=" + str(y))
    print("z=" + str(z))

Vous pouvez faire des choses comme:

>>> mylist = [1,2,3]
>>> foo(*mylist)
x=1
y=2
z=3

>>> mydict = {'x':1,'y':2,'z':3}
>>> foo(**mydict)
x=1
y=2
z=3

>>> mytuple = (1, 2, 3)
>>> foo(*mytuple)
x=1
y=2
z=3

Remarque: Les clés mydictdoivent être nommées exactement comme les paramètres de fonction foo. Sinon, il lancera un TypeError:

>>> mydict = {'x':1,'y':2,'z':3,'badnews':9}
>>> foo(**mydict)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got an unexpected keyword argument 'badnews'
Lorin Hochstein
la source
175

Le simple * signifie qu'il peut y avoir n'importe quel nombre d'arguments positionnels supplémentaires. foo()peut être invoqué comme foo(1,2,3,4,5). Dans le corps de foo () param2 se trouve une séquence contenant 2-5.

Le double ** signifie qu'il peut y avoir n'importe quel nombre de paramètres nommés supplémentaires. bar()peut être invoqué comme bar(1, a=2, b=3). Dans le corps de bar () param2 se trouve un dictionnaire contenant {'a': 2, 'b': 3}

Avec le code suivant:

def foo(param1, *param2):
    print(param1)
    print(param2)

def bar(param1, **param2):
    print(param1)
    print(param2)

foo(1,2,3,4,5)
bar(1,a=2,b=3)

la sortie est

1
(2, 3, 4, 5)
1
{'a': 2, 'b': 3}
nickd
la source
5
Peut-être un exemple supplémentaire avec foobar(param1, *param2, **param3)est nécessaire pour que cette réponse soit complète.
Aniket Thakur
1
@AniketThakur a ajouté la partie restante ici .
Raj
148

Que font **(double étoile) et *(étoile) pour les paramètres

Ils permettent aux fonctions à définir d'accepter et aux utilisateurs de passer n'importe quel nombre d'arguments, positional ( *) et keyword ( **).

Définition des fonctions

*argspermet un nombre illimité d'arguments positionnels (paramètres), qui seront attribués à un tuple nommé args.

**kwargspermet un nombre illimité d'arguments de mot-clé facultatifs (paramètres), qui seront dans un dict nommé kwargs.

Vous pouvez (et devez) choisir n'importe quel nom approprié, mais si l'intention est que les arguments soient de sémantique non spécifique argset kwargssoient des noms standard.

Expansion, passage d'un nombre quelconque d'arguments

Vous pouvez également utiliser *argset **kwargspour passer des paramètres à partir de listes (ou tout itérable) et de dict (ou de tout mappage), respectivement.

La fonction recevant les paramètres n'a pas besoin de savoir qu'ils sont développés.

Par exemple, xrange de Python 2 ne s'attend pas explicitement *args, mais puisqu'il prend 3 entiers comme arguments:

>>> x = xrange(3) # create our *args - an iterable of 3 integers
>>> xrange(*x)    # expand here
xrange(0, 2, 2)

Comme autre exemple, nous pouvons utiliser l'expansion de dict dans str.format:

>>> foo = 'FOO'
>>> bar = 'BAR'
>>> 'this is foo, {foo} and bar, {bar}'.format(**locals())
'this is foo, FOO and bar, BAR'

Nouveau dans Python 3: définition de fonctions avec des arguments de mots clés uniquement

Vous pouvez avoir des arguments de mot clé uniquement après que *args- par exemple, ici, kwarg2doit être donné comme argument de mot clé - et non positionnellement:

def foo(arg, kwarg=None, *args, kwarg2=None, **kwargs): 
    return arg, kwarg, args, kwarg2, kwargs

Usage:

>>> foo(1,2,3,4,5,kwarg2='kwarg2', bar='bar', baz='baz')
(1, 2, (3, 4, 5), 'kwarg2', {'bar': 'bar', 'baz': 'baz'})

En outre, *peut être utilisé par lui - même pour indiquer que les arguments que mot - clé suivent, sans tenir compte des arguments de position illimitée.

def foo(arg, kwarg=None, *, kwarg2=None, **kwargs): 
    return arg, kwarg, kwarg2, kwargs

Ici, kwarg2encore une fois, doit être un argument de mot clé explicitement nommé:

>>> foo(1,2,kwarg2='kwarg2', foo='foo', bar='bar')
(1, 2, 'kwarg2', {'foo': 'foo', 'bar': 'bar'})

Et nous ne pouvons plus accepter d'arguments positionnels illimités car nous n'avons pas *args*:

>>> foo(1,2,3,4,5, kwarg2='kwarg2', foo='foo', bar='bar')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() takes from 1 to 2 positional arguments 
    but 5 positional arguments (and 1 keyword-only argument) were given

Encore une fois, plus simplement, nous devons ici kwargêtre donnés par un nom, et non par position:

def bar(*, kwarg=None): 
    return kwarg

Dans cet exemple, nous voyons que si nous essayons de passer kwargpositionnellement, nous obtenons une erreur:

>>> bar('kwarg')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: bar() takes 0 positional arguments but 1 was given

Nous devons explicitement passer le kwargparamètre comme argument de mot clé.

>>> bar(kwarg='kwarg')
'kwarg'

Démos compatibles Python 2

*args(généralement **kwargsappelés "star-args") et (les étoiles peuvent être impliquées en disant "kwargs", mais être explicites avec "double-star kwargs") sont des idiomes courants de Python pour utiliser la notation *et **. Ces noms de variables spécifiques ne sont pas requis (par exemple, vous pouvez utiliser *fooset **bars), mais un écart par rapport à la convention est susceptible de faire enrager vos collègues codeurs Python.

Nous les utilisons généralement lorsque nous ne savons pas ce que notre fonction va recevoir ou combien d'arguments nous pouvons passer, et parfois même lorsque nommer chaque variable séparément deviendrait très compliqué et redondant (mais c'est un cas où généralement explicite est mieux qu'implicite).

Exemple 1

La fonction suivante décrit comment ils peuvent être utilisés et illustre le comportement. Notez que l' bargument nommé sera consommé par le deuxième argument positionnel avant:

def foo(a, b=10, *args, **kwargs):
    '''
    this function takes required argument a, not required keyword argument b
    and any number of unknown positional arguments and keyword arguments after
    '''
    print('a is a required argument, and its value is {0}'.format(a))
    print('b not required, its default value is 10, actual value: {0}'.format(b))
    # we can inspect the unknown arguments we were passed:
    #  - args:
    print('args is of type {0} and length {1}'.format(type(args), len(args)))
    for arg in args:
        print('unknown arg: {0}'.format(arg))
    #  - kwargs:
    print('kwargs is of type {0} and length {1}'.format(type(kwargs),
                                                        len(kwargs)))
    for kw, arg in kwargs.items():
        print('unknown kwarg - kw: {0}, arg: {1}'.format(kw, arg))
    # But we don't have to know anything about them 
    # to pass them to other functions.
    print('Args or kwargs can be passed without knowing what they are.')
    # max can take two or more positional args: max(a, b, c...)
    print('e.g. max(a, b, *args) \n{0}'.format(
      max(a, b, *args))) 
    kweg = 'dict({0})'.format( # named args same as unknown kwargs
      ', '.join('{k}={v}'.format(k=k, v=v) 
                             for k, v in sorted(kwargs.items())))
    print('e.g. dict(**kwargs) (same as {kweg}) returns: \n{0}'.format(
      dict(**kwargs), kweg=kweg))

Nous pouvons vérifier l'aide en ligne pour la signature de la fonction, avec help(foo), qui nous indique

foo(a, b=10, *args, **kwargs)

Appelons cette fonction avec foo(1, 2, 3, 4, e=5, f=6, g=7)

qui imprime:

a is a required argument, and its value is 1
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 2
unknown arg: 3
unknown arg: 4
kwargs is of type <type 'dict'> and length 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: g, arg: 7
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
4
e.g. dict(**kwargs) (same as dict(e=5, f=6, g=7)) returns: 
{'e': 5, 'g': 7, 'f': 6}

Exemple 2

Nous pouvons également l'appeler à l'aide d'une autre fonction, dans laquelle nous fournissons simplement a:

def bar(a):
    b, c, d, e, f = 2, 3, 4, 5, 6
    # dumping every local variable into foo as a keyword argument 
    # by expanding the locals dict:
    foo(**locals()) 

bar(100) impressions:

a is a required argument, and its value is 100
b not required, its default value is 10, actual value: 2
args is of type <type 'tuple'> and length 0
kwargs is of type <type 'dict'> and length 4
unknown kwarg - kw: c, arg: 3
unknown kwarg - kw: e, arg: 5
unknown kwarg - kw: d, arg: 4
unknown kwarg - kw: f, arg: 6
Args or kwargs can be passed without knowing what they are.
e.g. max(a, b, *args) 
100
e.g. dict(**kwargs) (same as dict(c=3, d=4, e=5, f=6)) returns: 
{'c': 3, 'e': 5, 'd': 4, 'f': 6}

Exemple 3: utilisation pratique dans les décorateurs

OK, peut-être que nous ne voyons pas encore l'utilitaire. Imaginez donc que vous ayez plusieurs fonctions avec du code redondant avant et / ou après le code de différenciation. Les fonctions nommées suivantes ne sont que des pseudo-codes à des fins d'illustration.

def foo(a, b, c, d=0, e=100):
    # imagine this is much more code than a simple function call
    preprocess() 
    differentiating_process_foo(a,b,c,d,e)
    # imagine this is much more code than a simple function call
    postprocess()

def bar(a, b, c=None, d=0, e=100, f=None):
    preprocess()
    differentiating_process_bar(a,b,c,d,e,f)
    postprocess()

def baz(a, b, c, d, e, f):
    ... and so on

Nous pouvons peut-être gérer cela différemment, mais nous pouvons certainement extraire la redondance avec un décorateur, et donc notre exemple ci-dessous montre comment *argset **kwargspeut être très utile:

def decorator(function):
    '''function to wrap other functions with a pre- and postprocess'''
    @functools.wraps(function) # applies module, name, and docstring to wrapper
    def wrapper(*args, **kwargs):
        # again, imagine this is complicated, but we only write it once!
        preprocess()
        function(*args, **kwargs)
        postprocess()
    return wrapper

Et maintenant, chaque fonction encapsulée peut être écrite de manière beaucoup plus succincte, comme nous avons pris en compte la redondance:

@decorator
def foo(a, b, c, d=0, e=100):
    differentiating_process_foo(a,b,c,d,e)

@decorator
def bar(a, b, c=None, d=0, e=100, f=None):
    differentiating_process_bar(a,b,c,d,e,f)

@decorator
def baz(a, b, c=None, d=0, e=100, f=None, g=None):
    differentiating_process_baz(a,b,c,d,e,f, g)

@decorator
def quux(a, b, c=None, d=0, e=100, f=None, g=None, h=None):
    differentiating_process_quux(a,b,c,d,e,f,g,h)

Et par affacturage notre code, *argset **kwargsnous permet de faire, nous réduisons les lignes de code, d' améliorer la lisibilité et la maintenabilité, et sont seuls endroits canoniques pour la logique de notre programme. Si nous devons changer une partie de cette structure, nous avons un endroit où effectuer chaque changement.

Aaron Hall
la source
48

Comprenons d'abord ce que sont les arguments positionnels et les arguments de mots clés. Voici un exemple de définition de fonction avec des arguments positionnels.

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(1,2,3)
#output:
1
2
3

Il s'agit donc d'une définition de fonction avec des arguments positionnels. Vous pouvez également l'appeler avec un mot clé / des arguments nommés:

def test(a,b,c):
     print(a)
     print(b)
     print(c)

test(a=1,b=2,c=3)
#output:
1
2
3

Étudions maintenant un exemple de définition de fonction avec des arguments de mots clés :

def test(a=0,b=0,c=0):
     print(a)
     print(b)
     print(c)
     print('-------------------------')

test(a=1,b=2,c=3)
#output :
1
2
3
-------------------------

Vous pouvez également appeler cette fonction avec des arguments positionnels:

def test(a=0,b=0,c=0):
    print(a)
    print(b)
    print(c)
    print('-------------------------')

test(1,2,3)
# output :
1
2
3
---------------------------------

Nous connaissons donc maintenant les définitions de fonctions avec des arguments de position et de mot-clé.

Étudions maintenant l'opérateur '*' et l'opérateur '**'.

Veuillez noter que ces opérateurs peuvent être utilisés dans 2 domaines:

a) appel de fonction

b) définition de la fonction

L'utilisation de l'opérateur '*' et de l'opérateur '**' dans l'appel de fonction.

Passons directement à un exemple, puis discutons-en.

def sum(a,b):  #receive args from function calls as sum(1,2) or sum(a=1,b=2)
    print(a+b)

my_tuple = (1,2)
my_list = [1,2]
my_dict = {'a':1,'b':2}

# Let us unpack data structure of list or tuple or dict into arguments with help of '*' operator
sum(*my_tuple)   # becomes same as sum(1,2) after unpacking my_tuple with '*'
sum(*my_list)    # becomes same as sum(1,2) after unpacking my_list with  '*'
sum(**my_dict)   # becomes same as sum(a=1,b=2) after unpacking by '**' 

# output is 3 in all three calls to sum function.

Alors souviens-toi

lorsque l'opérateur '*' ou '**' est utilisé dans un appel de fonction -

L'opérateur '*' décompresse la structure de données telle qu'une liste ou un tuple en arguments nécessaires à la définition de la fonction.

L'opérateur '**' décompresse un dictionnaire en arguments nécessaires à la définition de la fonction.

Étudions maintenant l'utilisation de l'opérateur '*' dans la définition de la fonction . Exemple:

def sum(*args): #pack the received positional args into data structure of tuple. after applying '*' - def sum((1,2,3,4))
    sum = 0
    for a in args:
        sum+=a
    print(sum)

sum(1,2,3,4)  #positional args sent to function sum
#output:
10

Dans la définition de fonction, l'opérateur '*' regroupe les arguments reçus dans un tuple.

Voyons maintenant un exemple de '**' utilisé dans la définition de fonction:

def sum(**args): #pack keyword args into datastructure of dict after applying '**' - def sum({a:1,b:2,c:3,d:4})
    sum=0
    for k,v in args.items():
        sum+=v
    print(sum)

sum(a=1,b=2,c=3,d=4) #positional args sent to function sum

Dans la définition de fonction L'opérateur '**' regroupe les arguments reçus dans un dictionnaire.

Alors souviens-toi:

Dans une fonction, la structure de données '*' décompresse le tuple ou la liste en arguments de position ou de mot clé à recevoir par définition de fonction.

Dans une fonction, appelez la structure de données du dictionnaire «**» pour décomposer les arguments positionnels ou mot-clé à recevoir par définition de fonction.

Dans une définition de fonction, le '*' regroupe les arguments positionnels dans un tuple.

Dans une définition de fonction, le '**' regroupe les arguments des mots clés dans un dictionnaire.

Karan Ahuja
la source
Explication vraiment propre, étape par étape et facile à suivre!
Aleksandar
merci Continuez à faire monter les votes. [Aussi pour plus de notes de ma part, je suis à @mrtechmaker sur twitter]
Karan Ahuja
32

Ce tableau est pratique pour utiliser *et **dans la construction de fonction et l' appel de fonction :

            In function construction         In function call
=======================================================================
          |  def f(*args):                 |  def f(a, b):
*args     |      for arg in args:          |      return a + b
          |          print(arg)            |  args = (1, 2)
          |  f(1, 2)                       |  f(*args)
----------|--------------------------------|---------------------------
          |  def f(a, b):                  |  def f(a, b):
**kwargs  |      return a + b              |      return a + b
          |  def g(**kwargs):              |  kwargs = dict(a=1, b=2)
          |      return f(**kwargs)        |  f(**kwargs)
          |  g(a=1, b=2)                   |
-----------------------------------------------------------------------

Cela ne fait que résumer la réponse de Lorin Hochstein, mais je la trouve utile.

En relation: les utilisations des opérateurs étoile / splat ont été étendues dans Python 3

Brad Solomon
la source
22

*et **ont un usage spécial dans la liste des arguments de fonction. * implique que l'argument est une liste et **implique que l'argument est un dictionnaire. Cela permet aux fonctions de prendre un nombre arbitraire d'arguments

ronak
la source
17

Pour ceux d'entre vous qui apprennent par des exemples!

  1. Le but de * est de vous donner la possibilité de définir une fonction qui peut prendre un nombre arbitraire d'arguments fournis sous forme de liste (par ex.f(*myList) ).
  2. Le but de **est de vous donner la possibilité de nourrir les arguments d'une fonction en fournissant un dictionnaire (par exemple f(**{'x' : 1, 'y' : 2})).

Montrons en définissant une fonction qui prend deux variables normales x, yet peut accepter plus d' arguments que myArgs, et peut accepter encore plus d' arguments que myKW. Plus tard, nous montrerons comment nourrir en yutilisant myArgDict.

def f(x, y, *myArgs, **myKW):
    print("# x      = {}".format(x))
    print("# y      = {}".format(y))
    print("# myArgs = {}".format(myArgs))
    print("# myKW   = {}".format(myKW))
    print("# ----------------------------------------------------------------------")

# Define a list for demonstration purposes
myList    = ["Left", "Right", "Up", "Down"]
# Define a dictionary for demonstration purposes
myDict    = {"Wubba": "lubba", "Dub": "dub"}
# Define a dictionary to feed y
myArgDict = {'y': "Why?", 'y0': "Why not?", "q": "Here is a cue!"}

# The 1st elem of myList feeds y
f("myEx", *myList, **myDict)
# x      = myEx
# y      = Left
# myArgs = ('Right', 'Up', 'Down')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# y is matched and fed first
# The rest of myArgDict becomes additional arguments feeding myKW
f("myEx", **myArgDict)
# x      = myEx
# y      = Why?
# myArgs = ()
# myKW   = {'y0': 'Why not?', 'q': 'Here is a cue!'}
# ----------------------------------------------------------------------

# The rest of myArgDict becomes additional arguments feeding myArgs
f("myEx", *myArgDict)
# x      = myEx
# y      = y
# myArgs = ('y0', 'q')
# myKW   = {}
# ----------------------------------------------------------------------

# Feed extra arguments manually and append even more from my list
f("myEx", 4, 42, 420, *myList, *myDict, **myDict)
# x      = myEx
# y      = 4
# myArgs = (42, 420, 'Left', 'Right', 'Up', 'Down', 'Wubba', 'Dub')
# myKW   = {'Wubba': 'lubba', 'Dub': 'dub'}
# ----------------------------------------------------------------------

# Without the stars, the entire provided list and dict become x, and y:
f(myList, myDict)
# x      = ['Left', 'Right', 'Up', 'Down']
# y      = {'Wubba': 'lubba', 'Dub': 'dub'}
# myArgs = ()
# myKW   = {}
# ----------------------------------------------------------------------

Avertissements

  1. ** est exclusivement réservé aux dictionnaires.
  2. L'affectation d'arguments non facultative se produit en premier.
  3. Vous ne pouvez pas utiliser deux fois un argument non facultatif.
  4. Le cas échéant, **doit venir après *, toujours.
Miladiouss
la source
14

De la documentation Python:

S'il y a plus d'arguments positionnels qu'il n'y a d'emplacements de paramètres formels, une exception TypeError est levée, sauf si un paramètre formel utilisant la syntaxe "* identificateur" est présent; dans ce cas, ce paramètre formel reçoit un tuple contenant les arguments positionnels en excès (ou un tuple vide s'il n'y avait pas d'arguments positionnels en excès).

Si un argument de mot clé ne correspond pas à un nom de paramètre formel, une exception TypeError est déclenchée, sauf si un paramètre formel utilisant la syntaxe "** identificateur" est présent; dans ce cas, ce paramètre formel reçoit un dictionnaire contenant les arguments de mots clés en excès (en utilisant les mots clés comme clés et les valeurs des arguments comme valeurs correspondantes), ou un (nouveau) dictionnaire vide s'il n'y avait pas d'arguments de mots clés en excès.

Chris Upchurch
la source
10

* signifie recevoir des arguments variables sous forme de tuple

** signifie recevoir des arguments variables sous forme de dictionnaire

Utilisé comme suit:

1) célibataire *

def foo(*args):
    for arg in args:
        print(arg)

foo("two", 3)

Production:

two
3

2) Maintenant **

def bar(**kwargs):
    for key in kwargs:
        print(key, kwargs[key])

bar(dic1="two", dic2=3)

Production:

dic1 two
dic2 3
ishandutta2007
la source
8

Je veux donner un exemple que d'autres n'ont pas mentionné

* peut également déballer un générateur

Un exemple du document Python3

x = [1, 2, 3]
y = [4, 5, 6]

unzip_x, unzip_y = zip(*zip(x, y))

unzip_x sera [1, 2, 3], unzip_y sera [4, 5, 6]

Le zip () reçoit plusieurs arguments iretable et renvoie un générateur.

zip(*zip(x,y)) -> zip((1, 4), (2, 5), (3, 6))
Lochu'an Chang
la source
7

En Python 3.5, vous pouvez également utiliser cette syntaxe list, dict, tupleet setaffiche (parfois appelés littéraux). Voir PEP 488: Généralisations de déballage supplémentaires .

>>> (0, *range(1, 4), 5, *range(6, 8))
(0, 1, 2, 3, 5, 6, 7)
>>> [0, *range(1, 4), 5, *range(6, 8)]
[0, 1, 2, 3, 5, 6, 7]
>>> {0, *range(1, 4), 5, *range(6, 8)}
{0, 1, 2, 3, 5, 6, 7}
>>> d = {'one': 1, 'two': 2, 'three': 3}
>>> e = {'six': 6, 'seven': 7}
>>> {'zero': 0, **d, 'five': 5, **e}
{'five': 5, 'seven': 7, 'two': 2, 'one': 1, 'three': 3, 'six': 6, 'zero': 0}

Il permet également de décompresser plusieurs itérables en un seul appel de fonction.

>>> range(*[1, 10], *[2])
range(1, 10, 2)

(Merci à mgilson pour le lien PEP.)

leewz
la source
1
Je ne suis pas sûr que ce soit une violation de "il n'y a qu'une seule façon de le faire". Il n'y a pas d'autre moyen d'initialiser une liste / tuple à partir de plusieurs itérables - Vous devez actuellement les enchaîner en un seul itérable qui n'est pas toujours pratique. Vous pouvez lire sur le rationnel dans PEP-0448 . De plus, ce n'est pas une fonctionnalité python3.x, c'est une fonctionnalité python3.5 + :-).
mgilson
@mgilson, cela expliquerait pourquoi cela n'a pas été mentionné auparavant.
leewz
6

En plus des appels de fonction, * args et ** kwargs sont utiles dans les hiérarchies de classes et évitent également d'avoir à écrire la __init__méthode en Python. Une utilisation similaire peut être vue dans des frameworks comme le code Django.

Par exemple,

def __init__(self, *args, **kwargs):
    for attribute_name, value in zip(self._expected_attributes, args):
        setattr(self, attribute_name, value)
        if kwargs.has_key(attribute_name):
            kwargs.pop(attribute_name)

    for attribute_name in kwargs.viewkeys():
        setattr(self, attribute_name, kwargs[attribute_name])

Une sous-classe peut alors être

class RetailItem(Item):
    _expected_attributes = Item._expected_attributes + ['name', 'price', 'category', 'country_of_origin']

class FoodItem(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['expiry_date']

La sous-classe doit ensuite être instanciée comme

food_item = FoodItem(name = 'Jam', 
                     price = 12.0, 
                     category = 'Foods', 
                     country_of_origin = 'US', 
                     expiry_date = datetime.datetime.now())

En outre, une sous-classe avec un nouvel attribut qui n'a de sens que pour cette instance de sous-classe peut appeler la classe Base __init__pour décharger le paramètre d'attributs. Cela se fait via * args et ** kwargs. kwargs est principalement utilisé pour que le code soit lisible à l'aide d'arguments nommés. Par exemple,

class ElectronicAccessories(RetailItem):
    _expected_attributes = RetailItem._expected_attributes +  ['specifications']
    # Depend on args and kwargs to populate the data as needed.
    def __init__(self, specifications = None, *args, **kwargs):
        self.specifications = specifications  # Rest of attributes will make sense to parent class.
        super(ElectronicAccessories, self).__init__(*args, **kwargs)

qui peut être créé comme

usb_key = ElectronicAccessories(name = 'Sandisk', 
                                price = '$6.00', 
                                category = 'Electronics',
                                country_of_origin = 'CN',
                                specifications = '4GB USB 2.0/USB 3.0')

Le code complet est ici

pingouin tranquille
la source
1
1. Fondamentalement, init est une méthode, donc (dans ce contexte) ce n'est pas vraiment différent. 2. Utilisez # pour les commentaires, pas "" ", qui marque juste les chaînes littérales. 3. Utiliser super devrait être la manière préférée, en particulier pour votre exemple avec l'héritage à plusieurs niveaux.
0xc0de
4

S'appuyant sur la réponse de Nickd ...

def foo(param1, *param2):
    print(param1)
    print(param2)


def bar(param1, **param2):
    print(param1)
    print(param2)


def three_params(param1, *param2, **param3):
    print(param1)
    print(param2)
    print(param3)


foo(1, 2, 3, 4, 5)
print("\n")
bar(1, a=2, b=3)
print("\n")
three_params(1, 2, 3, 4, s=5)

Production:

1
(2, 3, 4, 5)

1
{'a': 2, 'b': 3}

1
(2, 3, 4)
{'s': 5}

Fondamentalement, n'importe quel nombre d' arguments positionnels peut utiliser * args et tous les arguments nommés (ou kwargs aka arguments de mots clés) peuvent utiliser ** kwargs.

Raj
la source
3

*argset **kwargs: vous permettent de passer un nombre variable d'arguments à une fonction.

*args: est utilisé pour envoyer une liste d'arguments de longueur variable non mot-clé à la fonction:

def args(normal_arg, *argv):
    print("normal argument:", normal_arg)

    for arg in argv:
        print("Argument in list of arguments from *argv:", arg)

args('animals', 'fish', 'duck', 'bird')

Produira:

normal argument: animals
Argument in list of arguments from *argv: fish
Argument in list of arguments from *argv: duck
Argument in list of arguments from *argv: bird

**kwargs*

**kwargsvous permet de passer une longueur variable d'arguments mot-clé à une fonction. Vous devez utiliser **kwargssi vous souhaitez gérer des arguments nommés dans une fonction.

def who(**kwargs):
    if kwargs is not None:
        for key, value in kwargs.items():
            print("Your %s is %s." % (key, value))

who(name="Nikola", last_name="Tesla", birthday="7.10.1856", birthplace="Croatia")  

Produira:

Your name is Nikola.
Your last_name is Tesla.
Your birthday is 7.10.1856.
Your birthplace is Croatia.
Harvey
la source
2

Cet exemple vous aiderait à vous souvenir *args, **kwargset même à l' superhéritage en Python à la fois.

class base(object):
    def __init__(self, base_param):
        self.base_param = base_param


class child1(base): # inherited from base class
    def __init__(self, child_param, *args) # *args for non-keyword args
        self.child_param = child_param
        super(child1, self).__init__(*args) # call __init__ of the base class and initialize it with a NON-KEYWORD arg

class child2(base):
    def __init__(self, child_param, **kwargs):
        self.child_param = child_param
        super(child2, self).__init__(**kwargs) # call __init__ of the base class and initialize it with a KEYWORD arg

c1 = child1(1,0)
c2 = child2(1,base_param=0)
print c1.base_param # 0
print c1.child_param # 1
print c2.base_param # 0
print c2.child_param # 1
thanhtang
la source
1

Un bon exemple d'utilisation des deux dans une fonction est:

>>> def foo(*arg,**kwargs):
...     print arg
...     print kwargs
>>>
>>> a = (1, 2, 3)
>>> b = {'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(*a,**b)
(1, 2, 3)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,**b) 
((1, 2, 3),)
{'aa': 11, 'bb': 22}
>>>
>>>
>>> foo(a,b) 
((1, 2, 3), {'aa': 11, 'bb': 22})
{}
>>>
>>>
>>> foo(a,*b)
((1, 2, 3), 'aa', 'bb')
{}
amir jj
la source
1

TL; DR

Voici 6 cas d'utilisation différents pour *et **dans la programmation python:

  1. Pour accepter un certain nombre d'arguments de position en utilisant *args: def foo(*args): pass , ici fooaccepte un certain nombre d'arguments de position, à savoir, les appels suivants sont valides foo(1),foo(1, 'bar')
  2. Pour accepter un certain nombre d'arguments à l' aide de mots - clés **kwargs: def foo(**kwargs): pass , ici « foo » accepte un certain nombre d'arguments mot - clé, à savoir, les appels suivants sont valides foo(name='Tom'),foo(name='Tom', age=33)
  3. Pour accepter un certain nombre d'arguments de position et de mots clés en utilisant *args, **kwargs: def foo(*args, **kwargs): pass , ici fooaccepte un certain nombre d'arguments de position et de mots - clés, à savoir les appels suivants sont valides foo(1,name='Tom'),foo(1, 'bar', name='Tom', age=33)
  4. Pour appliquer mot - clé que les arguments en utilisant *: def foo(pos1, pos2, *, kwarg1): pass , ici *signifie que foo accepte uniquement les arguments clés après pos2, par conséquent foo(1, 2, 3)soulève TypeError mais foo(1, 2, kwarg1=3)est ok.
  5. Pour ne plus exprimer d'intérêt pour des arguments plus positionnels en utilisant *_(Remarque: ceci est une convention uniquement): def foo(bar, baz, *_): pass signifie (par convention) foon'utilise que des arguments baret bazdans son fonctionnement et ignorera les autres.
  6. Pour ne plus exprimer d'intérêt pour plus d'arguments de mots clés en utilisant \**_(Remarque: ceci est une convention uniquement): def foo(bar, baz, **_): pass signifie (par convention) foon'utilise que des arguments baret bazdans son fonctionnement et ignorera les autres.

BONUS: à partir de python 3.8, on peut utiliser /dans la définition de fonction pour appliquer des paramètres positionnels uniquement. Dans l'exemple suivant, les paramètres a et b sont uniquement positionnels , tandis que c ou d peut être positionnel ou mot-clé, et e ou f doivent être des mots-clés:

def f(a, b, /, c, d, *, e, f):
    pass
Meysam Sadeghi
la source
0

TL; DR

Il regroupe les arguments passés à la fonction dans listet dictrespectivement à l'intérieur du corps de la fonction. Lorsque vous définissez une signature de fonction comme celle-ci:

def func(*args, **kwds):
    # do stuff

il peut être appelé avec n'importe quel nombre d'arguments et d'arguments de mots clés. Les arguments non mot-clés sont regroupés dans une liste appelée argsà l'intérieur du corps de la fonction et les arguments mot-clés sont regroupés dans un dict appelé kwdsà l'intérieur du corps de la fonction.

func("this", "is a list of", "non-keyowrd", "arguments", keyword="ligma", options=[1,2,3])

maintenant à l'intérieur du corps de la fonction, lorsque la fonction est appelée, il y a deux variables locales, argsqui est une liste ayant une valeur ["this", "is a list of", "non-keyword", "arguments"]et kwdsqui est une dictvaleur ayant{"keyword" : "ligma", "options" : [1,2,3]}


Cela fonctionne également en sens inverse, c'est-à-dire du côté de l'appelant. par exemple si vous avez une fonction définie comme:

def f(a, b, c, d=1, e=10):
    # do stuff

vous pouvez l'appeler avec en déballant les itérables ou les mappages que vous avez dans la portée d'appel:

iterable = [1, 20, 500]
mapping = {"d" : 100, "e": 3}
f(*iterable, **mapping)
# That call is equivalent to
f(1, 20, 500, d=100, e=3)
RBF06
la source
0

Le contexte

  • python 3.x
  • déballage avec **
  • utiliser avec la mise en forme des chaînes

Utiliser avec la mise en forme des chaînes

En plus des réponses dans ce fil, voici un autre détail qui n'a pas été mentionné ailleurs. Cela élargit la réponse de Brad Solomon

Le décompactage avec **est également utile lors de l'utilisation de python str.format.

Ceci est quelque peu similaire à ce que vous pouvez faire avec la f-strings chaîne f de python mais avec la surcharge supplémentaire de déclaration d'un dict pour contenir les variables (la chaîne f ne nécessite pas de dict).

Exemple rapide

  ## init vars
  ddvars = dict()
  ddcalc = dict()
  pass
  ddvars['fname']     = 'Huomer'
  ddvars['lname']     = 'Huimpson'
  ddvars['motto']     = 'I love donuts!'
  ddvars['age']       = 33
  pass
  ddcalc['ydiff']     = 5
  ddcalc['ycalc']     = ddvars['age'] + ddcalc['ydiff']
  pass
  vdemo = []

  ## ********************
  ## single unpack supported in py 2.7
  vdemo.append('''
  Hello {fname} {lname}!

  Today you are {age} years old!

  We love your motto "{motto}" and we agree with you!
  '''.format(**ddvars)) 
  pass

  ## ********************
  ## multiple unpack supported in py 3.x
  vdemo.append('''
  Hello {fname} {lname}!

  In {ydiff} years you will be {ycalc} years old!
  '''.format(**ddvars,**ddcalc)) 
  pass

  ## ********************
  print(vdemo[-1])
dreftymac
la source
-2
  • def foo(param1, *param2): est une méthode qui peut accepter un nombre arbitraire de valeurs pour *param2 ,
  • def bar(param1, **param2): est une méthode qui peut accepter un nombre arbitraire de valeurs avec des clés pour *param2
  • param1 est un paramètre simple.

Par exemple, la syntaxe pour implémenter varargs en Java comme suit:

accessModifier methodName(datatype arg) {
    // method body
}
Premraj
la source