#Exercice 1
# Fonctions binaires
def add(a, b):
    return a + b

def sub(a, b):
    return a - b

def mul(a, b):
    return a * b


# Fonction qui prend une fonction en paramètre
def operation(f, a, b):
    return f(a, b)


# Tests
print(operation(add, 5, 3))  # 8
print(operation(sub, 5, 3))  # 2
print(operation(mul, 5, 3))  # 15

###########################################################
#Exercice 2
def Reduction(func):
    def wrapper(*args, **kwargs):
        prix = func(*args, **kwargs)
        prix_reduit = prix * 0.9  # réduction de 10 %
        return prix_reduit
    return wrapper


@Reduction
def prix_produit():
    return 100


print(prix_produit())  # 90.0

###########################################################
#Exercice 3
def verifier_type(func):
    def wrapper(*args, **kwargs):
        for arg in args:
            if not isinstance(arg, int):
                raise TypeError("Tous les arguments doivent être des entiers")
        return func(*args, **kwargs)
    return wrapper


@verifier_type
def addition(a, b):
    return a + b


print(addition(4, 5))  # 9
# print(addition(4, 5.5))  # Provoque une erreur
###########################################################
#Exercice 4

def journaliser(cls):
    original_init = cls.__init__

    def new_init(self, *args, **kwargs):
        print(f"Création d'une instance de {cls.__name__}")
        original_init(self, *args, **kwargs)

    cls.__init__ = new_init
    return cls


@journaliser
class Personne:
    def __init__(self, nom):
        self.nom = nom


p1 = Personne("Alice")
p2 = Personne("Bob")











