Question Que signifie l'opérateur star? [dupliquer]


Dupliquer possible: 
Que signifient * args et ** kwargs?

Que fait le * opérateur signifie en Python, comme dans le code comme zip(*x) ou f(**k)?

  1. Comment est-il géré en interne dans l'interprète?
  2. Cela affecte-t-il la performance? Est-ce rapide ou lent?
  3. Quand est-ce utile et quand n'est-ce pas?
  4. Devrait-il être utilisé dans une déclaration de fonction ou dans un appel?

460
2018-05-27 14:10


origine


Réponses:


La seule étoile * décompresse la séquence / collection en arguments positionnels, vous pouvez donc faire ceci:

def sum(a, b):
    return a + b

values = (1, 2)

s = sum(*values)

Cela va décompresser le tuple pour qu'il s'exécute réellement comme:

s = sum(1, 2)

La double étoile ** fait de même, n'utilisant qu'un dictionnaire et donc des arguments nommés:

values = { 'a': 1, 'b': 2 }
s = sum(**values)

Vous pouvez également combiner:

def sum(a, b, c, d):
    return a + b + c + d

values1 = (1, 2)
values2 = { 'c': 10, 'd': 15 }
s = sum(*values1, **values2)

va s'exécuter comme:

s = sum(1, 2, c=10, d=15)

Voir aussi la section 4.7.4 - Déballage des listes d'arguments de la documentation Python.


De plus, vous pouvez définir des fonctions à prendre *x et **y arguments, cela permet à une fonction d'accepter n'importe quel nombre d'arguments positionnels et / ou nommés qui ne sont pas spécifiquement nommés dans la déclaration.

Exemple:

def sum(*values):
    s = 0
    for v in values:
        s = s + v
    return s

s = sum(1, 2, 3, 4, 5)

ou avec **:

def get_a(**values):
    return values['a']

s = get_a(a=1, b=2)      # returns 1

Cela peut vous permettre de spécifier un grand nombre de paramètres optionnels sans avoir à les déclarer.

Et encore, vous pouvez combiner:

def sum(*values, **options):
    s = 0
    for i in values:
        s = s + i
    if "neg" in options:
        if options["neg"]:
            s = -s
    return s

s = sum(1, 2, 3, 4, 5)            # returns 15
s = sum(1, 2, 3, 4, 5, neg=True)  # returns -15
s = sum(1, 2, 3, 4, 5, neg=False) # returns 15

708
2018-05-27 14:15



Un petit point: ce ne sont pas des opérateurs. Les opérateurs sont utilisés dans les expressions pour créer de nouvelles valeurs à partir de valeurs existantes (1 + 2 devient 3, par exemple, les * et ** font partie de la syntaxe des déclarations de fonctions et des appels.


36
2018-05-27 16:43



C'est ce qu'on appelle la syntaxe d'appel étendu. Du Documentation:

Si l'expression syntaxique * apparaît dans l'appel de la fonction, l'expression doit être évaluée en une séquence. Les éléments de cette séquence sont traités comme s’ils étaient des arguments de position supplémentaires; s'il y a des arguments de position x1, ..., xN, et l'expression évalue à une séquence y1, ..., yM, cela équivaut à un appel avec M + N arguments de position x1, ..., xN, y1,. .., yM.

et:

Si l'expression syntaxe ** apparaît dans l'appel de la fonction, l'expression doit correspondre à un mappage dont le contenu est traité comme un argument supplémentaire. Dans le cas d'un mot clé apparaissant à la fois dans l'expression et en tant qu'argument de mot clé explicite, une exception TypeError est déclenchée.


15
2018-05-27 14:14



Je trouve cela particulièrement utile lorsque vous souhaitez «stocker» un appel de fonction.

Par exemple, supposons que j'ai des tests unitaires pour une fonction 'add':

def add(a, b): return a + b
tests = { (1,4):5, (0, 0):0, (-1, 3):3 }
for test, result in tests.items():
   print 'test: adding', test, '==', result, '---', add(*test) == result

Il n'y a pas d'autre moyen d'appeler add, sinon de faire manuellement quelque chose comme add (test [0], test [1]), qui est moche. En outre, s'il y a un nombre variable de variables, le code pourrait devenir très moche avec toutes les instructions if dont vous auriez besoin.

Un autre endroit utile est la définition d'objets Factory (objets qui créent des objets pour vous). Supposons que vous ayez une classe Factory, qui crée des objets Car et les renvoie. Vous pouvez faire en sorte que myFactory.make_car ('red', 'bmw', '335ix') crée Car ('red', 'bmw', '335ix'), puis le retourne.

def make_car(*args):
   return Car(*args)

Ceci est également utile lorsque vous souhaitez appeler un constructeur de superclasse.


13
2018-05-27 18:45



Dans une fonction, l'étoile unique transforme une liste en arguments séparés (par ex. zip(*x) est le même que zip(x1,x2,x3) si x=[x1,x2,x3]) et l'étoile double transforme un dictionnaire en arguments de mots-clés séparés (par ex. f(**k) est le même que f(x=my_x, y=my_y) si k = {'x':my_x, 'y':my_y}.

Dans une définition de fonction, c'est l'inverse: l'étoile unique transforme un nombre arbitraire d'arguments en liste, et le double départ transforme un nombre arbitraire d'arguments dans un dictionnaire. Par exemple. def foo(*x) signifie "foo prend un nombre arbitraire d'arguments et ils seront accessibles à travers la liste x (c'est-à-dire si l'utilisateur appelle foo(1,2,3), x sera [1,2,3])" et def bar(**k) signifie que "barre prend un nombre arbitraire d'arguments de mots clés et qu'ils seront accessibles via le dictionnaire k (c'est-à-dire si l'utilisateur appelle bar(x=42, y=23), k sera {'x': 42, 'y': 23}) ".


7
2018-05-27 14:13