21 Astuces Et Conceptss Python Utiles

Python est facile à écrire et à comprendre, mais tu peux rapidement l’utiliser de la mauvaise manière et te retrouver dans un champ de mines antipersonnel.

Cet article dresse une liste de 21 astuces concises qui amélioreront la lisibilité et l’efficacité de ton code. Ces conseils sont tirés de projets persos, de revues de code et de discussions inspirantes avec des dévs.

Que tu sois nouveau dans le langage Python ou déjà un développeur expérimenté, cet article devrait te permettre d’apprendre quelques petites choses.

Cette liste comprend des modèles communs à Python, des concepts de base et certaines des meilleures pratiques.
Comme les 21 astuces n’ont pas d’ordre prédéfini, n’hésite pas à passer directement aux sections qui t’intéressent.

Sans plus attendre, jetons un coup d’œil 👀

#1 – Opérateurs ternaires

Les opérateurs ternaires en Python permettent d’écrire des expressions conditionnelles en ligne. Ils sont particulièrement utiles lorsque tu dois affecter une valeur à une variable en fonction d’une condition.

age = 25
status = "Adulte" if age >= 18 else "Mineur"

print(status)
# Adulte

Dans cet exemple, la valeur de la variable status sera “Adulte” si age est supérieur ou égal à 18, sinon ce sera “Mineur”.

Les opérateurs ternaires sont utiles lorsqu’ils sont utilisés dans une compréhension de liste :

scores = [100, 46, 54, 23, 20, 99]
threshold = 50
results = ["admis" if score > threshold else "non admis" for score in scores]

print(results)    
# ['admis', 'non admis', 'admis', 'non admis', 'non admis', 'admis']

ou dans des fonctions lambda :

scores = [100, 46, 54, 23, 20, 99]
threshold = 50

results = map(lambda score: "admis" if score > threshold else "non admis", scores)
print(results)    
# ['admis', 'non admis', 'admis', 'non admis', 'non admis', 'admis']

#2 – Gestionnaires de contexte

Imagine que tu ouvres un fichier avec Python, que tu y écrives quelques lignes, puis qu’une exception se produise avant même que tu ne puisses le fermer.

Bien que cela ne semble pas être un problème pour un développeur débutant, cette situation maintient en mémoire une ressource qui n’est jamais nettoyée (un descripteur de fichier) et peut empêcher l’écriture d’une partie des données.

Les gestionnaires de contexte permettent d’éviter cela. Ils sont utilisés pour gérer les ressources et s’assurer qu’elles sont correctement initialisées et nettoyées.

Ils permettent d’écrire un code plus lisible et plus facile à maintenir en encapsulant la logique de gestion des ressources dans l’objet gestionnaire de contexte.

👉 Le gestionnaire de contexte le plus courant est celui que tu crées avec open

with open('file.txt', 'r') as file:
    # si un problème survient ici
    data = file.read()

La fonction open() renvoie un objet fichier qui agit comme un gestionnaire de contexte. Il ferme automatiquement le fichier lorsque le bloc à l’intérieur de l’instruction with est quitté, assurant ainsi un nettoyage adéquat.

Tu peux également utiliser des gestionnaires de contexte dans d’autres situations :

👉 Connexions à une base de données :

with psycopg2.connect(database='mydb') as conn:
    cursor = conn.cursor()
    cursor.execute('SELECT * FROM table')
    results = cursor.fetchall()

Dans cet exemple, la méthode connect() de la bibliothèque psycopg2 renvoie un objet de connexion qui agit comme un gestionnaire de contexte qui ferme automatiquement la connexion lorsque le bloc est quitté.

👉 Ressources de verrouillage :

import threading
lock = threading.Lock()
def some_function():
    with lock:
        # Section critique du code

Ici, l’objet Lock() du module de threading est utilisé comme gestionnaire de contexte pour garantir qu’un seul thread peut accéder à la section critique du code à la fois.

#3 – Création de ses propres gestionnaires de contexte !

Il peut arriver que tu doives définir ton propre gestionnaire de contexte.

Pour ce faire, tu dois définir une classe qui implémente les méthodes __enter__() et __exit__() :

  • __enter__() est appelée lorsque l’exécution est lancée avec le bloc with
  • __exit__() est appelée lorsque l’exécution quitte le bloc de code with

Voici un exemple de gestionnaire de contexte personnalisé qui mesure le temps d’exécution d’un bloc de code :

Exemple 1 : Un timer

import time

class Timer:
    def __enter__(self):
        self.start_time = time.time()
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        elapsed_time = time.time() - self.start_time
        print(f"Durée d'exécution : {elapsed_time} secondes")
21 astuces et concepts Python pour améliorer ton code : codage d'un Timer

Cet exemple est assez simple. Examinons-en un autre pour imiter le comportement d’open.

Exemple 2 : Un ouvreur de fichiers personnalisé

class WritableFile:
    def __init__(self, file_path):
        self.file_path = file_path

    def __enter__(self):
        print("ouverture d'un fichier")
        self.file_obj = open(self.file_path, mode="w")
        return self.file_obj

    def __exit__(self, exc_type, exc_val, exc_tb):
        if self.file_obj:
            self.file_obj.close()
        print("fichier fermé avec succès)


# f correspond à ce que la méthode __enter__ renvoie
with WritableFile("./test.txt") as f:
    pass
21 astuces et concepts Python pour améliorer ton code : un ouvreur de fichierrss personnalisé

Bien que ces exemples soient assez simples, ils devraient te donner un exemple de code de départ pour construire des gestionnaires de contexte plus avancés où le nettoyage des ressources est effectué de manière appropriée.

#4 – Enumerate

Si tu souhaites itérer sur une séquence tout en gardant une trace de l’index de chaque élément, tu dois utiliser la fonction enumerate.

Elle rend le code plus concis en éliminant la nécessité de gérer manuellement une variable d’index distincte.

fruits = ['pomme', 'banane', 'orange']
for index, fruit in enumerate(fruits):
    print(f"Index : {index}, Fruit : {fruit}")

# Index : 0, Fruit : pomme
# Index : 1, Fruit : banane
# Index : 2, Fruit : orange

#5 – Zip

La fonction zip permet d’itérer sur plusieurs séquences simultanément :

names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for name, age in zip(names, ages):
    print(f"Prénom : {name}, Âge : {age}")

# Prénom : Alice, Âge : 25
# Prénom : Bob, Âge : 30
# Prénom : Charlie, Âge : 35

Dans un cas d’utilisation intéressant, zip peut également créer un dictionnaire à partir de deux listes, où les clés proviennent de la première liste et les valeurs de la seconde.

keys = ['a', 'b', 'c']
values = [1, 2, 3]
my_dict = dict(zip(keys, values))
print(my_dict)

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

#6 – Trier des objets complexes avec sorted

La fonction sorted permet de trier des objets complexes en fonction de certains de leurs attributs.

Pour accéder à la valeur de l’attribut à trier, tu dois utiliser une fonction clé personnalisée.

Supposons que tu souhaites classer ces personnes en fonction de la clé “age”.

people = [
    {'name': 'Alice', 'age': 25},
    {'name': 'Bob', 'age': 30},
    {'name': 'Charlie', 'age': 20}
]

Il suffit de définir l’argument clé pour qu’il pointe vers les valeurs d’âge.

sorted_people = sorted(people, key=lambda x: x['age'])
print(sorted_people)

# [{'name': 'Charlie', 'age': 20}, {'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}] 

Il en va de même si les dictionnaires sont remplacés par des objets :

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

people = [
    Person('Alice', 25),
    Person('Bob', 30),
    Person('Charlie', 20)

]
sorted_people = sorted(people, key=lambda x: x.age)
print([person.name for person in sorted_people])

print(sorted_people)

# ['Charlie', 'Alice', 'Bob']

#7 – Économiser de la mémoire avec les générateurs

Les générateurs Python sont un type d’itérable qui peut être utilisé pour générer une séquence de valeurs à la volée, sans les stocker toutes en mémoire en même temps. Ils sont définis en utilisant le mot-clé yield au lieu de return.

Voici un générateur simple qui calcule les nombres de Fibonacci.

def fibonacci_generator():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

L’appel de cette fonction ne l’exécute pas réellement. Elle crée et renvoie plutôt un objet generator.

fib = fibonacci_generator()

fib 
# <generator object fibonacci_generator at 0x7fea39c31890>

Cet objet générateur ne génère des valeurs de Fibonacci que lorsqu’il est transmis à la fonction next.

next(fb)
# 0
next(fb)
# 1
next(fb)
# 1
next(fb)
# 2

Ou itérée à l’aide d’une boucle for (qui appelle en fait la fonction suivante sous le capot).

Cette méthode est économe en mémoire car elle évite de générer la totalité de la séquence (infinie) en amont.

Un cas d’utilisation naturel des générateurs est la lecture d’un grand ensemble de données ligne par ligne (ou morceau par morceau).

def read_large_file(filename):
    with open(filename, 'r') as file:
        for line in file:
            yield line

file_generator = read_large_file('large_file.txt')

# traiter ligne par ligne au lieu de charger le fichier complet

for line in file_generator:
    process_line(line)  # Traitement

#8 – Améliorez le formatage des chaînes de caractères avec les f-strings !

Les f-strings améliorent la syntaxe de formatage des chaînes : il s’agit de chaînes littérales avec un f au début et des accolades contenant des expressions qui seront remplacées par leurs valeurs.

La syntaxe est assez simple.

name = "Alice"
age = 25
print(f"Hello {name}, tu as {age} ans !")  

# Hello Alice, tu as 25 ans!

Tu peux même l’utiliser pour évaluer des expressions arbitraires, telles que des appels de fonction :

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

x = 5
y = 3
print(f"La somme de {x} et {y} est {add_numbers(x, y)}.")  
# Output: La somme de 5 et 3 est 8.

Des flottants avec une précision particulière :

pi = 3.14159265359
print(f"La valeur de pi est approximativement {pi:.2f}.")  
# Output: La valeur de pi est approximativement 3.14.

Objets.

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

person = Person("Bob", 25)
print(f"Prénom : {person.name}, Âge : {person.age}")  
# Output: Prénom : Bob, Âge : 25

Dictionnaires (guillemets simples autour des clés du dictionnaire) :

>>> data_scientist = {'name': 'Rod PARIS', 'age': 35}
>>> f"Ce data scientist est {data_scientist['name']}, âgé de {data_scientist['age']} ans."

 Ce data scientist est Rod PARIS, agé de 35 ans.

#9 – Construire des objets itérables en utilisant le protocole iterator

Est-ce que tu t’es déjà demandé comment les simples boucles for fonctionnent en coulisses ?

La réponse ne se trouve pas dans la boucle for elle-même, mais plutôt dans les objets qui sont itérés (c’est-à-dire les itérables). Il peut s’agir de listes, de dicts ou d’ensembles.

En fait, les itérables supportent le protocole itérateur et implémentent les méthodes dunder __iter__() et __next()__.

Ces méthodes sont les méthodes de base qui permettent d’itérer sur une collection d’éléments ou d’effectuer des itérations personnalisées.

Voici un itérateur personnalisé qui prend une liste de nombres et génère leurs carrés à la volée :

class SquareIterator:
    def __init__(self, numbers):
        self.numbers = numbers
        self.index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.index >= len(self.numbers):
            raise StopIteration
        square = self.numbers[self.index] ** 2
        self.index += 1
        return square
  • La méthode __iter__() renvoie l’objet iterator lui-même. Cette méthode est appelée lorsque l’itérateur est initialisé.
  • Dans la méthode __next__(), définis la logique de récupération de l’élément suivant dans l’itération. Cette méthode doit lever l’exception StopIteration lorsqu’il n’y a plus d’éléments à itérer. (remarque que l’index est incrémenté à cet ensemble pour garder une trace de sa position)

Nous pouvons utiliser cet itérateur personnalisé comme suit :

numbers = [1, 2, 3, 4, 5]
iterator = SquareIterator(numbers)

for square in iterator:
    print(square)

# 1
# 4
# 9
# 16
# 25

#10 – Créer des classes d’exceptions personnalisées pour documenter ton code

Je n’ai jamais pensé à créer des classes d’exception personnalisées. Je me suis contenté des classes intégrées.

En réalité, le fait d’avoir des classes d’exception dans une base de code importante présente de nombreux avantages.

  • Elles te permettent de créer des exceptions plus spécifiques et plus significatives qui représentent avec précision l’erreur ou la condition exceptionnelle qui se produit dans ton code. Cela facilite le débogage.
  • Elles améliorent la collaboration : si tes collègues commencent à pousser du code dans le même repo, il est plus facile pour eux de déboguer l’erreur avec un message explicite plutôt que d’avoir une exception ValueError générique.

Voici un exemple de classe d’exception personnalisée qui est levée lorsqu’une chaîne d’entrée est plus longue qu’une valeur seuil.

class NameTooLongError(Exception):
    """Custom exception for names that are too long."""
    def __init__(self, name, max_length):
        self.name = name
        self.max_length = max_length
        super().__init__(f"Name '{name}' est trop long. La longueur maximale autorisée est de {max_length} caractères.")

def process_name(name):
    max_length = 10  # Maximum allowed name length
    if len(name) > max_length:
        raise NameTooLongError(name, max_length)
    else:
        print("Traitement du nom réussi :, name)

# Example usage
try:
    input_name = "AVeryLongName"
    process_name(input_name)
except NameTooLongError as e:
    print("Error:", e)

#11 – setattr et getattr pour interagir dynamiquement avec les classes

Les méthodes setattr et getattr de Python sont des fonctions intégrées qui permettent de définir et d’obtenir dynamiquement les attributs d’un objet, respectivement.

setattr :
setattr(obj, name, value) définit l’attribut name de l’objet obj à la valeur donnée.

Si l’attribut n’existe pas, setattr crée un nouvel attribut.

class Person:
    pass

person = Person()
setattr(person, "name", "John")
setattr(person, "age", 25)

print(person.name)  
# John
print(person.age)   
# 25

Si tu essayes d’accéder à un attribut inexistant, tu obtiendras une erreur de type AttributeError.

 print(getattr(person, "address"))

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
Input In [26], in <cell line: 8>()
      6 print(getattr(person, "name"))      # Output: John
      7 print(getattr(person, "age"))       # Output: 25
----> 8 print(getattr(person, "address"))   # Output: AttributeError
      9 print(getattr(person, "address", "N/A"))

AttributeError: 'Person' object has no attribute 'address'

Pour éviter ce problème, il convient de fournir une valeur par défaut :

print(getattr(person, "address", "N/A"))
# N/A

#12 – Le véritable objectif de l’underscore

As-tu déjà vu des traits de soulignement (_ ) utilisés dans du code Python ?

Il y a peut-être une raison à cela.

En Python, les underscores sont des variables spéciales qui sont utilisées comme des espaces réservés pour des valeurs inutiles ou ignorées.

Voici quelques exemples d’utilisation des caractères de soulignement :

✅  Ignorer une valeur lors de l’unpacking :

_, age, _ = ("John", 25, "USA") print(age) # Output: 25

✅ Suppression d’une variable de boucle :

numbers = [1, 2, 3, 4, 5]
for _ in numbers:
    print("Bouclage...")

✅ Ignorer les valeurs de retour des fonctions :

def calculate_values():
    # ... quelques calculs ...
    return result1, result2, result3

_, important_result, _ = calculate_values()

✅ Placeholder dans les arguments de fonction non utilisés :

def process_data(data, _):
    # ... traitement dess données ...

process_data(my_data, _)

#13 – Un aperçu de la programmation fonctionnelle avec map, filter et reduce

map, filter et reduce sont des fonctions intégrées à Python qui opèrent sur des itérables.

👉 map

La fonction map applique une fonction donnée (premier argument) à chaque élément d’une table itérative (deuxième argument) et renvoie un itérateur avec les résultats.

numbers = [1, 2, 3, 4, 5]
squared_numbers = map(lambda x: x**2, numbers)
print(list(squared_numbers))  

# [1, 4, 9, 16, 25]

C’est l’équivalent exact de l’extrait de code suivant :

numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for number in numbers:
    squared_numbers.append(number ** 2)
print(squared_numbers)

# [1, 4, 9, 16, 25]

👉 filter

La fonction filter crée un itérateur qui filtre les éléments d’un itérable (deuxième argument) en fonction d’une condition donnée (premier argument).

numbers = [1, 2, 3, 4, 5]
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))  

# [2, 4]

C’est l’équivalent exact de l’extrait de code suivant :

numbers = [1, 2, 3, 4, 5]
even_numbers = []
for number in numbers:
    if number % 2 == 0:
        even_numbers.append(number)

print(even_numbers)

# [2, 4]

👉 reduce

La fonction reduce applique une fonction donnée aux éléments d’un itérable de manière cumulative, en les réduisant à une valeur unique.

from functools import reduce

numbers = [1, 2, 3, 4, 5]
sum_of_numbers = reduce(lambda x, y: x + y, numbers)
print(sum_of_numbers)  

# 15

#14 – Décomposition de séquences (et échange de variables)

Le déballage de variables en Python vous permet d’assigner plusieurs valeurs d’un itérable à plusieurs variables en une seule ligne.

Tu peux l’utiliser pour échanger des variables :

a = 10
b = 20
a, b = b, a
print(a, b)  
# 20 10

Déballer des tuples ou des listes :

point = (3, 4)
x, y = point
print(x, y)  
# 3 4

ou les valeurs de retour des fonctions :

def get_name():
    return "John", "Doe"

first_name, last_name = get_name()
print(first_name, last_name)  
# John Doe

#15 – Compter les itérables avec Counter

Tu peux compter les objets hachables en utilisant la classe collections.Counter en Python.

from collections import Counter

my_list = [1, 2, 3, 2, 1, 3, 4, 5, 1]
count = Counter(my_list)
print(count)  

# Counter({1: 3, 2: 2, 3: 2, 4: 1, 5: 1})

Le fait de disposer d’un objet Counter te permet d’accéder à des méthodes utiles telles que most_common, qui produit une liste de tuples dont le premier élément est une valeur et le second son nombre.

count.most_common(2)
# [(1, 3), (2, 2)]

#16 – Représentation des chaînes d’objets avec __str__ et __repr__

Les méthodes __str__ et __repr__ de Python sont utilisées pour fournir des représentations sous forme de chaîne de caractères d’un objet. La principale différence entre elles est leur objectif et le public auquel elles s’adressent.

Commençons par la classe suivante :

class Person(object):
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age

person = Person("john", "does", 30)


print(person)
# <__main__.Person object at 0x7fea39945b20>

Note que l’impression de l’objet ne donne pas une belle représentation. Au lieu de cela, elle montre l’adresse mémoire qui lui a été allouée.

  • La méthode __str__ peut modifier ce comportement :
class Person(object):
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age


    def __str__(self):
        return f"{self.first_name} {self.last_name} ({self.age})"

person = Person("john", "does", 30)
print(person)

# john does (30)

Cependant, si tu inspectes cet objet à partir de l’interpréteur de code, tu obtiendras le formatage précédent :

person
<__main__.Person at 0x7fea399ca3d0>

Pour éviter cela, tu dois implémenter la méthode __repr__ :

class Person(object):
    def __init__(self, first_name, last_name, age):
        self.first_name = first_name
        self.last_name = last_name
        self.age = age


    def __repr__(self):
        return f"{self.first_name} {self.last_name} ({self.age})"


person = Person("john", "does", 30)
# john does (30)

Maintenant, si tu veux imprimer cet objet, tu obtiendras le même formatage agréable.

print(person)
# john does (30)

Ce que j’en retiens est simple :

  • __str__ et __repr__ contrôlent la représentation des chaînes de caractères
  • tu peux ajouter une méthode __repr__ à tes classes, car l’implémentation de __str__ la prendra par défaut.

#17 – Utilisation de groupby dans itertools

Lorsque tu souhaites regrouper un itérable par clé, tu peux utiliser la fonction groupby de la bibliothèque intégrée itertools.

Considérons la forme la plus simple des itérables : une chaîne de caractères (une string).

from itertools import groupby

code = "BBEDBACEAEBACBDEDACC"

grouped = groupby(code, key=None)

for key, group in grouped:
    print(f"key: {key} | group : {list(group)}")

# key: B | group : ['B', 'B']
# key: E | group : ['E']
# key: D | group : ['D']
# key: B | group : ['B']
# key: A | group : ['A']
# key: C | group : ['C']
# key: E | group : ['E']
# key: A | group : ['A']
# key: E | group : ['E']
# key: B | group : ['B']
# key: A | group : ['A']
# key: C | group : ['C']
# key: B | group : ['B']
# key: D | group : ['D']
# key: E | group : ['E']
# key: D | group : ['D']
# key: A | group : ['A']
# key: C | group : ['C', 'C']

La fonction groupby parcourt la chaîne et chaque fois qu’elle voit une séquence de lettres identiques consécutives, elle les regroupe sous une seule touche (la première lettre).

La méthode groupby est plus utile lorsque tu trriees l’itérable avant : cela te permettra d’avoir tous les groupes distincts des mêmes éléments.

from itertools import groupby

code = "AAAABBBBBCCCCDDDEEEE"

grouped = groupby(code, key=None)

for key, group in grouped:
    print(f"key: {key} | group : {list(group)}")

# key: A | group : ['A', 'A', 'A', 'A']
# key: B | group : ['B', 'B', 'B', 'B', 'B']
# key: C | group : ['C', 'C', 'C', 'C']
# key: D | group : ['D', 'D', 'D']
# key: E | group : ['E', 'E', 'E', 'E']

Tu peux également utiliser groupby sur d’autres itérables.

from itertools import groupby

workers = [
 {'name': 'john', 'department': 'IT'},
 {'name': 'joe', 'department': 'finance'},
 {'name': 'alice', 'department': 'IT'},
 {'name': 'jack', 'department': 'legal'},
 {'name': 'meredith', 'department': 'finance'}
]

workers = sorted(data, key=lambda d: d["department"])

grouped = groupby(workers, key=lambda d: d["department"])

for key, group in grouped:
    print(f"key: {key} | group : {list(group)}")

# key: IT | group : [{'name': 'john', 'department': 'IT'}, {'name': 'alice', 'department': 'IT'}]
# key: finance | group : [{'name': 'joe', 'department': 'finance'}, {'name': 'meredith', 'department': 'finance'}]
# key: legal | group : [{'name': 'jack', 'department': 'legal'}]

#18 – Utilisation de la mémoire cache pour optimiser les appels de fonction

Si tu souhaites éviter les appels de fonction inutiles, en particulier si la sortie ne change pas avec les mêmes entrées pendant un certain temps, tu peux utiliser la mise en cache.

La mise en cache permet de stocker le résultat de la fonction et de le réutiliser ultérieurement.

import requests
from functools import lru_cache


@lru_cache()
def fetch_data(url):
    content = requests.get(url).content
    return content

url = "https://www.bbc.com/news/world-us-canada-66489815"

%%time
data = fetch_data(url)

# CPU times: user 28.2 ms, sys: 16.7 ms, total: 44.9 ms
# Wall time: 135 ms

%%time 
data = fetch_data(url)

# CPU times: user 4 µs, sys: 0 ns, total: 4 µs
# Wall time: 8.11 µs

%%time 
data = fetch_data(url)

# CPU times: user 6 µs, sys: 1e+03 ns, total: 7 µs
# Wall time: 10 µs

As-tu remarqué le temps d’exécution entre le premier appel et les deux autres ?

#19 – Fonctions lambda

Les fonctions lambda sont des fonctions anonymes qu’il n’est pas nécessaire de lier à un nom.

Par exemple, voici comment définir une fonction lambda pour effectuer une addition :

add = lambda x, y: x + y
add(10, 2)
# 12

Conceptuellement, cette fonction lambda est l’équivalent d’une fonction normale que tu déclarerais avec le mot-clé def.

def add(x, y):
    return x + y

mais écrites en ligne.

Les fonctions lambda ont une valeur de retour implicite et sont utiles lorsque tu les passes en tant qu’arguments à d’autres fonctions. Voici quelques exemples d’utilisation :

  • la programmation fonctionnelle avec map (fonctionne également avec filter et reduce)
product_names = ["Iphone 15", "iphone 14 ", " iphone 15", "IPHONE 13"]
clean_product_names = map(lambda name: name.strip().lower(), product_names)
print(list(clean_product_names)

# ['iphone 15', 'iphone 14', 'iphone 15', 'iphone 13']
  • fonctions clés dans sorted
employees = [
  {"id": 1, "salary": 95000},
  {"id": 2, "salary": 123050},
  {"id": 3, "salary": 64000},
  {"id": 4, "salary": 80000},
  {"id": 5, "salary": 45000},
  {"id": 6, "salary": 55000},
]

employees_sorted_by_salary = sorted(employees, key=lambda employee: employee["salary"])

print(employees_sorted_by_salary)
# [{'id': 5, 'salary': 45000},
#  {'id': 6, 'salary': 55000},
#  {'id': 3, 'salary': 64000},
#  {'id': 4, 'salary': 80000},
#  {'id': 1, 'salary': 95000},
#  {'id': 2, 'salary': 123050}]

#20 – Utilisation de la chaîne de itertools

Pour fusionner des listes de listes à l’aide de la fonction chain du module itertools, tu peux suivre cet exemple de code :

from itertools import chain

# Exemples de listes de listes
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Fusionner les listes à l'aide d'une chaîne
merged_list = list(chain(*list_of_lists))
print(merged_list)

# [1, 2, 3, 4, 5, 6, 7, 8, 9]

#21 – Fusionner des dictionnairres avec l’unpacking

Dans Python 3.5 et les versions ultérieures, tu peux utiliser l’unpacking de dictionnaire pour fusionner des dictionnaires.

dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}

merged_dict = {**dict1, **dict2}
print(merged_dict)

Conclusion

Si tu es arrivé jusqu’ici, je te remercie de ta lecture et j’espère que tu as au moins appris une chose ou deux. N’hésite pas à me dire dans les commentaires ci-dessous si tu penses à d’autres astuces Python utiles !

Publications similaires

0 Commentaires
Le plus récent
Le plus ancien Le plus populaire
Commentaires en ligne
Afficher tous les commentaires