web-dev-qa-db-fra.com

Qu'est-ce que l'opérateur star signifie?

Que signifie l'opérateur * en Python, tel qu'un code tel que 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 ne l'est-il pas?
  4. Devrait-il être utilisé dans une déclaration de fonction ou dans un appel?
540
psihodelia

L'étoile unique * décompresse la séquence/la collection en arguments de position. Vous pouvez ainsi:

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

values = (1, 2)

s = sum(*values)

Cela décompactera le tuple afin qu’il s’exécute comme suit:

s = sum(1, 2)

La double étoile ** fait la même chose, en utilisant uniquement 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)

s'exécutera comme:

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

Voir également la section 4.7.4 - Décompression des listes d’arguments de la documentation Python.


De plus, vous pouvez définir des fonctions pour prendre les arguments *x et **y, ce qui permet à une fonction d'accepter un nombre quelconque d'arguments de position et/ou nommés qui ne sont pas nommés spécifiquement 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 facultatifs 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

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, par exemple, devient 3. Les * et ** ici font partie de la syntaxe des déclarations de fonction et des appels.

40
Ned Batchelder

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, autre que de faire manuellement quelque chose comme add (test [0], test [1]), ce qui est moche. De plus, s'il y a un nombre variable de variables, le code pourrait devenir assez moche avec toutes les instructions if dont vous auriez besoin.

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

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

Ceci est également utile lorsque vous souhaitez appeler le constructeur d'une super-classe.

17
Donald Miner

Cela s'appelle la syntaxe d'appel étendue. De la documentation :

Si la syntaxe * expression apparaît dans l'appel de fonction, expression doit correspondre à une séquence. Les éléments de cette séquence sont traités comme s'il s'agissait d'arguments de position supplémentaires. s'il existe des arguments de position x1, ..., xN et que l'expression est évaluée à une séquence y1, ..., yM, cela équivaut à un appel avec M + N arguments de position x1, ..., xN, y1,. .., yM.

et:

Si la syntaxe ** expression apparaît dans l'appel de fonction, expression doit correspondre à un mappage dont le contenu est traité comme un argument de mot clé 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
Mark Byers

Dans un appel de fonction, l’étoile unique transforme une liste en arguments distincts (par exemple, Zip(*x) est identique à Zip(x1,x2,x3) si x=[x1,x2,x3]) et l’étoile double transforme un dictionnaire en arguments mot clé distincts (par exemple, f(**k) est identique à 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 qui se produit: l'étoile unique transforme un nombre arbitraire d'arguments en liste et le double début, transforme un nombre arbitraire d'arguments de mots clés en dictionnaire. Par exemple. def foo(*x) signifie "foo prend un nombre arbitraire d'arguments et ils seront accessibles via la liste x (c'est-à-dire si l'utilisateur appelle foo(1,2,3), x sera [1,2,3])" et def bar(**k) signifie "bar prend un nombre arbitraire d'arguments de mots clés qui seront accessibles via le dictionnaire k (c'est-à-dire si l'utilisateur appelle bar(x=42, y=23), k sera {'x': 42, 'y': 23})" .

13
sepp2k