• Assurez la sécurité des applications de la bonne manière! Détectez, protégez, surveillez, accélérez et plus encore…
  • Python est le langage de programmation le plus utilisé. Aujourd'hui, vous apprendrez à utiliser l'une de ses fonctionnalités principales, mais souvent ignorées, en la décompressant en Python.

    Vous avez probablement vu * et ** dans le code d'autres personnes ou même les avez utilisés sans vraiment savoir à quoi ils servent. Nous allons parcourir le concept de déballage et comment l'utiliser pour écrire plus de code Pythonic.

    Voici une liste de concepts qui vous seront utiles en lisant ce tutoriel :

    • Iterable: toute séquence pouvant être itérée par un boucle for, comme les ensembles, listes, tuples et dictionnaires
    • Appelable: Un objet Python qui peut être appelé en utilisant une double parenthèse (), par exemple, mafonction()
    • Coquille: Environnement d'exécution interactif qui nous permet d'exécuter du code Python. Nous pouvons l'appeler en exécutant "python" dans un terminal
    • Variable: Nom symbolique qui stocke un objet et a un emplacement mémoire réservé.

    Commençons par la confusion la plus fréquente : les astéristiques en Python sont aussi des opérateurs arithmétiques. Un astérisque (*) est utilisé pour la multiplication, tandis que deux d'entre eux (**) font référence à l'exponentiation.

    Nous pouvons le prouver en ouvrant un shell Python et en tapant :

    >>> 3*3
    9
    >>> 3**3
    27
    

    Remarque : Vous devez avoir installé Python 3 pour suivre ce didacticiel. Si vous ne l'avez pas installé, consultez notre Guide d'installation Python.

    Comme vous pouvez le voir, nous utilisons l'astérisque après le premier chiffre et avant le second. Quand vous voyez cela, cela signifie que nous utilisons les opérateurs arithmétiques.

    D'autre part, nous utilisons les astérisques (*, **) avant un itérable pour le décompresser — par exemple :

    >>> *range(1, 6),
    (1, 2, 3, 4, 5)
    >>> {**{'vanilla':3, 'chocolate':2}, 'strawberry':2}
    {'vanilla': 3, 'chocolate': 2, 'strawberry': 2}
    

    Ne vous inquiétez pas si vous ne l'obtenez pas, ce n'est qu'un préambule au déballage en Python. Alors allez-y et lisez l'intégralité du tutoriel !

    What’s unpacking?

    Le déballage est le processus consistant à extraire des éléments - des éléments itérables tels que des listes, des tuples et des dictionnaires. Pensez-y comme ouvrir une boîte et sortir différents objets comme des câbles, casque audio, ou une clé USB.

    Image de la boîte de déballage
    Le déballage en Python est similaire au déballage d'une boîte dans la vraie vie.

    Traduisons ce même exemple en code pour une meilleure compréhension :

    >>> mybox = ['cables', 'headphones', 'USB']
    >>> item1, item2, item3 = mybox

    Comme vous pouvez le voir, nous attribuons les trois éléments à l'intérieur du Ma boîte liste à trois variables article1, article2, article2. Ce type d'affectation de variable est le concept fondamental du déballage en Python.

    Si vous essayez d'obtenir la valeur de chaque élément, vous remarquerez que item1, fait référence à des « câbles », item2, fait référence à « écouteurs » et ainsi de suite.

    >>> item1
    'cables'
    >>> item2
    'headphones'
    >>> item3
    'USB'

    Jusqu'ici, tout semble aller bien avec ce code, mais que se passe-t-il si nous voulons décompresser une liste avec plus d'éléments — en gardant le même nombre de variables affectées ?

    >>> newbox = ['cables', 'headphones', 'USB', 'mouse']
    >>> item1, item2, item3 = newbox
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: too many values to unpack (expected 3)

    Vous vous attendiez probablement à ce genre d'erreur. Essentiellement, nous attribuons 4 éléments de liste à trois variables, comment Python parvient-il à attribuer les bonnes valeurs ?

    Ce n'est pas le cas, c'est parce que nous obtenons un Erreur de valeur avec le message "trop ​​de valeurs à décompresser". Cela se produit parce que nous définissons trois variables à gauche, et quatre valeurs (correspondant à la liste newbox) à droite.

    Si vous essayez de faire un processus similaire, mais avec plus de variables que de valeurs à décompresser, vous obtiendrez un autre Erreur de valeur sauf qu'avec un message un peu différent :

    >>> lastbox = ['cables', 'headphones']
    >>> item1, item2, item3 = lastbox
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: not enough values to unpack (expected 3, got 2)
    

    Remarque : Nous avons travaillé avec des listes, mais vous pouvez utiliser cette forme de décompression avec n'importe quel itérable (listes, ensembles, tuples, dictionnaires)

    Alors comment surmonter cette situation ? Existe-t-il un moyen de décompresser tous les éléments d'un itérable en quelques variables sans obtenir d'erreurs ?

    Bien sûr, et cela s'appelle opérateur de déballage ou opérateur astérisque (*, **). Voyons comment l'utiliser en Python.

    How to Unpack Lists With the * operator

    L'opérateur astérisque (*) est utilisé pour décompresser toutes les valeurs d'un itérable qui n'ont pas encore été affectées.

    Supposons que vous vouliez obtenir le premier et le dernier élément d'une liste sans utiliser d'index, nous pourrions le faire avec l'opérateur astérisque :

    >>> first, *unused, last = [1, 2, 3, 5, 7]
    >>> first
    1
    >>> last
    7
    >>> unused
    [2, 3, 5]
    

    Comme vous pouvez le constater, nous obtenons toutes les valeurs inutilisées avec l'opérateur astérisque. La meilleure façon de supprimer des valeurs est d'utiliser une variable de soulignement (_), qui est parfois utilisée comme une « variable factice ».

    >>> first, *_, last = [1, 2, 3, 5, 7]
    >>> _
    [2, 3, 5]
    

    On peut toujours utiliser cette astuce même si la liste ne comporte que deux éléments :

    >>> first, *_, last = [1, 2]
    >>> first
    1
    >>> last
    2
    >>> _
    []

    Dans ce cas, la variable de soulignement (variable factice) stocke une liste vide afin que les deux autres variables qui l'entourent puissent accéder aux valeurs disponibles de la liste.

    Dépannage courant

    Nous pouvons décompresser un élément unique d'un itérable. Par exemple, vous arriveriez à quelque chose comme ceci :

    >>> *string = 'PythonIsTheBest'

    Cependant, le code ci-dessus renverra un Erreur de syntaxe:

    >>> *string = 'PythonIsTheBest'
      File "<stdin>", line 1
    SyntaxError: starred assignment target must be in a list or tuple
    

    Ceci parce que selon le Spécification PEP:

    Un tuple (ou une liste) sur le côté gauche d'un devoir simple

    Si nous voulons décompresser toutes les valeurs d'un itérable dans une seule variable, nous devons configurer un tuple, donc ajouter une simple virgule suffira :

    >>> *string, = 'PythonIsTheBest'
    >>> string
    ['P', 'y', 't', 'h', 'o', 'n', 'I', 's', 'T', 'h', 'e', 'B', 'e', 's', 't']
    

    Un autre exemple serait d'utiliser le gamme fonction, qui renvoie une séquence de nombres.

    >>> *numbers, = range(5)
    >>> numbers
    [0, 1, 2, 3, 4]
    

    Maintenant que vous savez comment décompresser les listes et les tuples avec un astérisque, il est temps de vous lancer dans le décompression des dictionnaires.

    How to Unpack Dictionaries With ** operator

    Alors qu'un seul astérisque est utilisé pour décompresser les listes et les tuples, le double astérisque (**) est utilisé pour décompresser les dictionnaires.

    Malheureusement, nous ne pouvons pas décompresser un dictionnaire en une seule variable comme nous l'avons fait avec les tuples et les listes. Cela signifie que ce qui suit générera une erreur :

    >>> **greetings, = {'hello': 'HELLO', 'bye':'BYE'} 
    ...
    SyntaxError: invalid syntax
    

    Cependant, nous pouvons utiliser l'opérateur ** à l'intérieur des callables et d'autres dictionnaires. Par exemple, si nous voulons créer un dictionnaire fusionné, fait à partir d'autres dictionnaires, nous pourrions utiliser le code ci-dessous :

    >>> food = {'fish':3, 'meat':5, 'pasta':9} 
    >>> colors = {'red': 'intensity', 'yellow':'happiness'}
    >>> merged_dict = {**food, **colors}
    >>> merged_dict
    {'fish': 3, 'meat': 5, 'pasta': 9, 'red': 'intensity', 'yellow': 'happiness'}

    C'est un moyen assez court pour créer des dictionnaires composés, cependant, ce n'est pas l'approche principale du déballage en Python.

    Voyons comment nous pouvons utiliser le déballage avec des callables

    Packing in Functions: args and kwargs

    Vous avez probablement déjà vu args et kwargs implémentés sur des classes ou des fonctions. Voyons pourquoi devons-nous les utiliser avec des callables.

    Emballage avec l'opérateur * (args)

    Supposons que nous ayons une fonction qui calcule le produit de deux nombres.

    >>> def product(n1, n2):
    ...     return n1 * n2
    ... 
    >>> numbers = [12, 1]
    >>> product(*numbers)
    12
    

    Comme vous pouvez le voir, nous déballons la liste numéros à la fonction, nous exécutons donc en fait ce qui suit :

    >>> product(12, 1)
    12
    

    Jusqu'ici, tout fonctionne très bien, mais si on voulait passer une liste plus longue ? Cela générera certainement une erreur car la fonction reçoit plus d'arguments qu'elle n'est capable d'en gérer.

    >>> numbers = [12, 1, 3, 4]
    >>> product(*numbers)
    ...
    TypeError: product() takes 2 positional arguments but 4 were given
    

    Nous pouvons résoudre tout cela simplement en emballage la liste directement sur la fonction, ce qui crée un itérable à l'intérieur et nous permet de passer n'importe quel nombre d'arguments à la fonction.

    >>> def product(*args):
    ...     result = 1
    ...     for i in args:
    ...             result *= i
    ...     return result
    ...
    >>> product(*numbers)
    144
    

    Ici, nous traitons le args paramètre comme un itérable, parcourant ses éléments et renvoyant le produit de tous les nombres. Notez que le numéro de départ du résultat doit être un car si nous commençons par zéro, la fonction renverra toujours zéro.

    Remarque : args n'est qu'une convention, vous pouvez utiliser n'importe quel autre nom de paramètre

    Nous pourrions également passer des nombres arbitraires à la fonction sans utiliser de liste, tout comme avec la fonction intégrée fonction d'impression.

    >>> product(5, 5, 5)
    125
    >>> print(5, 5, 5)
    5 5 5

    Enfin, obtenons le type d'objet du args d'une fonction.

    >>> def test_type(*args):
    ...     print(type(args))
    ...     print(args)
    ... 
    >>> test_type(1, 2, 4, 'a string')
    <class 'tuple'>
    (1, 2, 4, 'a string')
    

    Comme indiqué dans le code ci-dessus, le type de args sera toujours tuple, et le contenu de celui-ci sera tous les arguments sans mot-clé passés à la fonction.

    Emballage avec l'opérateur ** (kwargs)

    Comme nous l'avons vu précédemment, l'opérateur ** est utilisé exclusivement pour les dictionnaires. Cela signifie qu'avec cet opérateur, nous pouvons transmettre des paires clé-valeur à la fonction en tant que paramètre.

    Créons une fonction faire_personne, qui reçoit un argument positionnel « nom » et une quantité indéfinie d'arguments à mots-clés.

    >>> def make_person(name, **kwargs):
    ...     result = name + ': '
    ...     for key, value in kwargs.items():
    ...             result += f'{key} = {value}, '
    ...     return result
    ... 
    >>> make_person('Melissa', id=12112, location='london', net_worth=12000)
    'Melissa: id = 12112, location = london, net_worth = 12000, '
    

    Comme vous pouvez le voir, la ** kwargs L'instruction convertit tous les arguments à mots-clés en un dictionnaire, que nous pouvons itérer à l'intérieur de la fonction.

    Remarque : kwargs est juste une convention, vous pouvez nommer ce paramètre avec ce que vous voulez

    Nous pouvons vérifier le type de kwargs de la même manière que nous l'avons fait avec args:

    >>> def test_kwargs(**kwargs):
    ...     print(type(kwargs))
    ...     print(kwargs)
    ... 
    >>> test_kwargs(random=12, parameters=21)
    <class 'dict'>
    {'random': 12, 'parameters': 21}
    

    Le kwargs La variable interne se transforme toujours en un dictionnaire, qui stocke les paires clé-valeur transmises à la fonction.

    Enfin, utilisons args reçues par les enchanteurs et permettent aussi kwargs dans la même fonction :

    >>> def my_final_function(*args, **kwargs):
    ...     print('Type args: ', type(args))
    ...     print('args: ', args)
    ...     print('Type kwargs: ', type(kwargs))
    ...     print('kwargs: ', kwargs)
    ... 
    >>> my_final_function('Python', 'The', 'Best', language='Python', users='A lot')
    Type args:  <class 'tuple'>
    args:  ('Python', 'The', 'Best')
    Type kwargs:  <class 'dict'>
    kwargs:  {'language': 'Python', 'users': 'A lot'}
    

    Conclusion

    Les opérateurs de déballage sont vraiment utiles dans les tâches quotidiennes, vous savez maintenant comment les utiliser à la fois dans les instructions individuelles et les paramètres de fonction.

    Dans ce tutoriel vous avez appris :

    • Vous utilisez * pour les tuples et les listes et ** pour les dictionnaires
    • Vous pouvez utiliser des opérateurs de décompression dans les constructeurs de fonctions et de classes
    • args sont utilisés pour passer des paramètres sans mots-clés aux fonctions
    • kwargs sont utilisés pour passer des paramètres à mots-clés aux fonctions.