Cours
La plupart d'entre nous utilisent les astérisques comme opérateurs de multiplication et de puissance, mais ils offrent aussi un large éventail d'opérations lorsqu'ils sont utilisés comme opérateurs préfixes en Python. Après lecture, vous connaîtrez l'ensemble des usages des astérisques.
Les astérisques ont de nombreux cas d'usage spécifiques en Python. En général, nous connaissons les opérateurs de multiplication et de puissance. Ils permettent aussi d'autres opérations comme le dépaquetage, le passage d'arguments, etc., selon les situations. Commençons par les usages généraux des astérisques.
Utilisation générale de * et **
* sert d'opérateur de multiplication tandis que ** est l'opérateur de puissance.
## declaring variables
a, b = 2,3
## multiplication
print("Multiplication of 2 and 3 is {}".format(a * b))
## as power operator
print("2 power 3 is {}".format(a ** b))
Multiplication of 2 and 3 is 6
2 power 3 is 8
Vous venez de voir l'usage le plus courant des astérisques. Il existe toutefois des cas d'utilisation des astérisques que vous ne connaissez peut‑être pas. Voyons comment en tirer parti.
1. Dépaquetage avec *
Dépaqueter les éléments d'une liste/tuple/ensemble à l'aide de *. Nous allons utiliser ce dépaquetage dans le code à venir pour illustrer d'autres fonctionnalités des astérisques. Le dépaquetage est l'idée de base derrière l'utilisation des astérisques comme opérateurs préfixes.
Supposons que nous voulions affecter le premier élément de la liste/du tuple/de l'ensemble à a et les éléments restants à b. En général, on le ferait avec du slicing.
## general approach
nums = [i for i in range(1, 6)]
a = nums[0]
b = nums[1:]
print(a, b)
print("--------------------------")
## hard approach
squares = [i ** 2 for i in range(1, 6)]
a = squares[0]
b = []
for i in range(1, len(squares)):
b.append(squares[i])
print(a, b)
1 [2, 3, 4, 5]
--------------------------
1 [4, 9, 16, 25]
Nous allons maintenant utiliser l'opérateur * pour réaliser cela en une seule ligne de code.
nums = [i for i in range(1, 6)]
## a will be 1 and b will be a list containing remaining elements
a, *b = nums
print(a, b)
1 [2, 3, 4, 5]
Ici, a est un scalaire extrait de la liste et b est une liste. Le dépaquetage fonctionne de la même manière avec les tuples et ensembles qu'avec les listes. Voyons quelques exemples.
## using tuple
## here first element will assign to a and last element to c
a, *b, c = (1, 2, 3, 4, 5)
print(a, b, c)
print("--------------------------")
## using sets
a, *b, c = {1, 4, 9, 16, 25}
print(a, b, c)
1 [2, 3, 4] 5
--------------------------
1 [4, 9, 16] 25
1.1. Combiner différents itérables
On peut ajouter deux itérables différents dans des listes/ensembles/tuples via le dépaquetage. En général, il faudrait convertir les itérables avant de les combiner. Avec *, ce n'est pas nécessaire. Exemple :
## combining a tuple, list, set
nums = [1, 2, 3]
nums2 = (4, 5, 6)
nums3 = {7, 8, 9}
## we convert the combined elements into any iterable we want
## here i am converting into a list
_list = [*nums, *nums2, *nums3]
_tuple = (*nums, *nums2, *nums3)
_set = {*nums, *nums2, *nums3}
print(type(_list))
print(_list)
print("------------------------")
print(type(_tuple))
print(_tuple)
print("------------------------")
print(type(_set))
print(_set)
<class 'list'>
[1, 2, 3, 4, 5, 6, 8, 9, 7]
------------------------
<class 'tuple'>
(1, 2, 3, 4, 5, 6, 8, 9, 7)
------------------------
<class 'set'>
{1, 2, 3, 4, 5, 6, 7, 8, 9}
1.2. Dépaquetage imbriqué
Le dépaquetage imbriqué consiste à extraire des éléments au premier niveau des éléments déjà extraits. Voyez l'exemple pour comprendre l'idée.
languages = ["Python", "HTML", "CSS", "JS"]
## unpacking
[[first_letter, *remaining], *other] = languages
print(first_letter, remaining, other)
P ['y', 't', 'h', 'o', 'n'] ['HTML', 'CSS', 'JS']
2. Dépaquetage avec **
Comme vu plus haut, ** permet de dépaqueter les éléments d'un dictionnaire. Il faut connaître les clés du dictionnaire pour extraire les valeurs lors du dépaquetage. Exemple :
## sample dictionary
person = {"name":"John", "age":19, "year_of_passing":"2021"}
string = "Name:-{name} Year Of Graduation:-{year_of_passing} Age:-{age}".format(**person)
print(string)
Name:-John Year Of Graduation:-2021 Age:-19
Il est peu courant d'utiliser ** pour extraire des éléments d'un dictionnaire.
3. Astérisques dans les fonctions
On peut passer et capter des arguments avec des astérisques dans les fonctions afin de réduire le nombre de lignes de code.
3.1. Dépaquetage dans les fonctions
L'opérateur * permet d'appeler une fonction en dépaquetant un itérable. Disons que nous avons une liste et que nous devons passer tous ses éléments séparément à print(). Que feriez‑vous ? Vous pensez sans doute à une boucle. Mais * simplifie grandement la tâche.
Il suffit de passer l'itérable sous la forme *nom_iterable. Il le dépaquette et transmet tous les éléments séparément.
nums = [i for i in range(1, 6)]
## passsing list using the *
print(*nums)
1 2 3 4 5
nums = (i for i in range(1, 6))
## passsing tuple using the *
print(*nums, sep = ", ")
1, 2, 3, 4, 5
3.2. Paquetage d'éléments
Paqueter signifie capturer plusieurs éléments d'un coup. On utilise cette fonctionnalité dans les appels de fonction.
def average(*nums):
return sum(nums) / len(nums)
Nous pouvons maintenant passer n'importe quel nombre d'entiers pour calculer la moyenne. La fonction average capture tous les arguments dans une liste.
## calling the average with some numbers
print(average(1, 2, 3, 4, 5))
3.0
Nous avons vu comment capturer plusieurs éléments dans une liste avec *. Voyons maintenant comment capturer des paires clé‑valeur avec **.
def _object(name, **properties):
print(name, properties)
_object("Car", color="Red", cost=999999, company="Ferrari")
Car {'ceo': 'Louis', 'color': 'Red', 'cost': 999999, 'company': 'Ferrari'}
4. Arguments nommés uniquement avec des arguments positionnels
Les arguments fournis avec leur nom sont des arguments nommés (keyword). Les autres sont des arguments positionnels. Commencez par bien distinguer arguments nommés et positionnels. Exemple :
## name is a positional argument
## color and cost are keyword arguments
def sample(car, color = None, cost = None):
print("Car:-{} Color:-{}, Cost:-{}".format(car, color, cost))
Pour les arguments nommés, on peut utiliser le nom du paramètre lors de l'appel de fonction. Si l'on ne fournit rien pour les arguments nommés, ils prennent la valeur par défaut définie dans la fonction.
On peut préciser les arguments nommés via leur nom ou via leur position.
sample("Ferrari", "Red", 999999)
Car:-Ferrari Color:-Red, Cost:-999999
sample("Ferrari", cost = 999999, color = "Red")
Car:-Ferrari Color:-Red, Cost:-999999
L'ordre des arguments nommés n'a pas d'importance si on les passe via les noms définis dans la fonction.
sample("Ferrari", color = "Green")
Car:-Ferrari Color:-Green, Cost:-None
Vous avez maintenant compris la différence entre arguments positionnels et arguments nommés. Passons au sujet principal.
Les arguments keyword-only ne peuvent être fournis que via des mots‑clés. On ne peut pas les définir positionnellement comme précédemment. Il faut déclarer les arguments keyword-only après l'argument * pour qu'ils soient capturés comme tels.
def keyword_only(*items, _list, default = False):
print(items)
print(_list)
print(default)
Il faut utiliser les mots‑clés _list et default lors de l'appel de la fonction, puisqu'ils viennent après *items. Sans mots‑clés, une erreur sera levée. Voyons les deux cas.
nums = [i ** 2 for i in range(1, 6)]
## calling the function
keyword_only(1, 2, 3, 4, 5, _list = nums, default = True)
(1, 2, 3, 4, 5)
[1, 4, 9, 16, 25]
True
Et si nous appelions la fonction keyword_only avec des arguments positionnels ?
nums = [i ** 2 for i in range(1, 6)]
## calling the function will raise an error
keyword_only(1, 2, 3, 4, 5, nums, False)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-85-bf737d8a8bfc> in <module>()
1 nums = [i ** 2 for i in range(1, 6)]
----> 2 keyword_only(1, 2, 3, 4, 5, nums, False)
TypeError: keyword_only() missing 1 required keyword-only argument: '_list'
L'erreur indique qu'il manque un argument requis de type keyword-only. Il faut donc utiliser des mots‑clés pour appeler les arguments keyword-only. Les arguments keyword-only sont définis uniquement après l'argument * dans les fonctions.
5. Arguments keyword-only sans arguments positionnels
Si l'on veut n'accepter que des arguments keyword-only sans aucun argument positionnel, Python permet d'utiliser * dans les paramètres de fonction pour y parvenir. Exemple :
def _sample(*, name):
print(name)
La fonction ci‑dessus n'accepte que des arguments keyword-only. Il faut passer l'argument avec le mot‑clé, sinon une erreur sera levée. Le * dans la définition impose que la fonction n'accepte des arguments que via des mots‑clés. Tout paramètre défini après * doit être fourni avec un mot‑clé lors de l'appel.
## calling the function using keyword 'name'
_sample(name = "Datacamp")
Datacamp
## calling the function without using keyword 'name'
## we will get a TypeError
_sample("Datacamp")
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-12-fe0d3718b56c> in <module>()
1 ## calling the function without using keyword 'name'
2 ## we will get a TypeError
----> 3 samp("Datacamp")
TypeError: samp() takes 0 positional arguments but 1 was given
Il est clair que la fonction _sample() n'accepte que des arguments keyword-only*.
Conclusion
À chaque nouvelle version de Python, des fonctionnalités sont ajoutées. Les astérisques sont particulièrement utiles et simplifient certaines parties du code. On ne peut pas accepter plusieurs arguments positionnels sans *, et les arguments keyword-only nécessitent aussi * pour être mis en place. D'autres opérations avec les astérisques sont possibles mais demanderaient plusieurs lignes de code. Entraînez‑vous pour bien les maîtriser. Merci de votre lecture !
Pour aller plus loin sur Python, suivez le cours Python Data Science Toolbox (Part 1) de DataCamp.
Bon code !