diff --git a/TP3/README.md b/TP3/README.md index adb5297..68bdfe1 100644 --- a/TP3/README.md +++ b/TP3/README.md @@ -1,3 +1,123 @@ # TP3 - Orienté Objet -TODO +## Exercices 1 + +Utiliser [person.py](./person.py). + +#### 1.1 Ajouter des attributs + +Rajouter les attributs `email` et `phone` à la classe `Person` et ajouter ce code à `main`: +```py +print(f"Email: {john.email}") +print(f"Phone: {john.phone}") +``` + +#### 1.2 Method `__str__` + +Exécuter `print(john)` dans `main` + +```py +def __str__(self) -> str: + return f"{self.first_name} {self.last_name}" +``` + +Exécuter `print(john)` dans `main` à nouveau. + +## Exercice 2 + +Utiliser [person_2.py](./person_2.py). + +Rajouter une ligne au niveau du TODO pour obtenir la sortie suivante : +``` +Is John of age: True +Is Bob of age: True +Change the age of majority to 32 +Is John of age: False +Is Bob of age: True +``` +Cette ligne ne **doit pas utiliser les objets `john` ou `bob`** + +## Exercice 3 + +Utiliser [vectors.py](./vectors.py). + +#### 3.1 Création des classes + +Un vecteur du plan est composé d'un point de départ et d'un point d'arrivé. +Créez une classe `Point` et une classe `Vector` de manière à représenter des points et des vecteurs du plan en Python. +Vérifier que la fonction `main` s'exécute sans erreurs et que les éléments affichés sont mathématiquements corrects. + + +#### 3.2 Produit scalaire + +Ajouter une méthode qui calcule le produit scalaire de deux vecteurs. + + +#### 3.3 Ajouter des méthodes spéciales + +Ajouter la méthode spéciale `__str__` aux deux classes. Résultat attendu : +```sh +print(point_A) # "Point(-2, -1)" +print(vector_AB) # "Vector(5, 8)" +``` + +Ensuite, ajouter les méthodes séciales à la classe `Vector`: +- `__add__` +- `__sub__` +- `__neg__` +- `__mul__` +Vérifier que la fonction `main_2` s'exécute sans erreurs et vérifier que les résultats sont mathématiquement corrects. + +Pour les annotations de types, on pourra utiliser le type `Self` +```py +from typing import Self +``` + +#### 3.4 Constructeur alternatif + +On souhaite pouvoir créer un vecteur en donnant à l'initialisation seulement le point d'arrivé. Dans ce cas, le point de départ sera l'origine. +On souhaite que ce code fonctionne : +```py +vector_OB = Vector.from_origin(point_B) +``` + +En utilisant une **méthode de class**, implémenter la méthode `from_origin` sur la classe `Vector`. + + +## Exercice 4 + +Utiliser [threads.py](./threads.py). + +#### 4.1 Exécuter et comprendre le code + +Jusqu'à présent, les programmes que nous avons écrit s'exécutaient dans un seul thread (le thread principal). Exécuter du code dans un nouveau thread permet d'exécuter ce code **en parallèle**. +Il y a plusieurs manières de créer un thread en Python. Pour ce TP, nous allons nous créer une classe qui **hérite de `threading.Thread`**. `threading.Thread` contient plusieurs méthodes et attributs utiles : +- `my_thread.is_alive()`: renvoie True si le thread est en cours d'exécution, False sinon +- `my_thread.start()`: crée le thread et commence l'exécution du code de la méthode `run` +- `my_thread.run()`: code exécuté dans le thread. +- `my_thread.run()`: code exécuté dans le thread. +- `my_thread.join()`: block l'exécution (attend) jusqu'á ce que `my_thread` ait fini (jusqu'à que ce `my_thread.run` ait fini). + +A noter qu'un thread ne peut être démarré qu'une seule fois ! + +Lisez le code, exécutez-le et comprenez son fonctionnement. Vous pouvez changer les valeurs des `time.sleep` et observer le résultat. + +Resources pour aller plus loin après le TP : +- https://realpython.com/intro-to-python-threading/ + +#### 4.2 Factorisation + +Le code actuel contient plusieurs problèmes : +- "magic values" pour 1s et 3s utilisés dans time.sleep(...) +- "magic values" pour 1 et 3 utilisés dans for i in range(...) +- duplications de code : les deux classes sont quasi identiques + +Factorisez ces deux classes en une seule pour enlever la duplication de code. Pour éviter d'hardcoder les valeurs cités plus haut, passez-les en paramètre de l'initialiseur. +Exemple de code main: +```py +counter1_thread = Counter(stop_value=10, sleep_delay_s=1) # count from 0 to 10 with 1s delay +counter2_thread = Counter(50, 3) # count from 0 to 50 with 3s delay +counter3_thread = Counter(20) # count from 0 to 20 with 1s delay (1s is the default) +``` + +Vous devrez pour cela *overrider* la méthode `__init__`. Pensez à appeler `super()__init__()`. diff --git a/TP3/person.py b/TP3/person.py new file mode 100644 index 0000000..f947c7d --- /dev/null +++ b/TP3/person.py @@ -0,0 +1,27 @@ +"""Representation of a person.""" + + +class Person: + def __init__(self, first_name: str, last_name: str, age: int , mail: str, phone: str) -> None: + self.first_name = first_name.capitalize() + self.last_name = last_name.upper() + self.age = age + self.mail= mail + self.phone= phone + def __str__(self)->str: + return f"{self.first_name} {self.last_name}" + + +def main(): + john = Person("John", "Doe", 30, "john.doe@uha.fr", "+33 06 82 72 22 76") + print(f"First name: {john.first_name}") + print(f"Last name: {john.last_name}") + print(f"Age: {john.age}") + print(f"mail: {john.mail}") + print(f"Phone number: {john.phone}") + print(john) + + +if __name__ == "__main__": + main() + diff --git a/TP3/person_2.py b/TP3/person_2.py new file mode 100644 index 0000000..bc389b6 --- /dev/null +++ b/TP3/person_2.py @@ -0,0 +1,34 @@ +"""Representation of a person.""" + + +class Person: + + AGE_MAJORITY = 18 + + def __init__(self, first_name: str, last_name: str, age: int) -> None: + self.first_name = first_name.capitalize() + self.last_name = last_name.upper() + self.age = age + + def is_of_age(self) -> bool: + """Return if the person is over the age of majority or not.""" + return self.age >= self.AGE_MAJORITY + + +def main(): + john = Person("John", "Doe", 30) + bob = Person("Bob", "Smith", 34) + + print(f"Is John of age: {john.is_of_age()}") + print(f"Is Bob of age: {bob.is_of_age()}") + + print("Change the age of majority to 32") + # TODO + Person.AGE_MAJORITY=32 + + print(f"Is John of age: {john.is_of_age()}") + print(f"Is Bob of age: {bob.is_of_age()}") + + +if __name__ == "__main__": + main() diff --git a/TP3/threads.py b/TP3/threads.py new file mode 100644 index 0000000..f5cfcd2 --- /dev/null +++ b/TP3/threads.py @@ -0,0 +1,54 @@ +"""Training with threads.""" + +import time +from threading import Thread + + +class Counter1(Thread): + """Thread counting with 1s delay.""" + + def start(self) -> None: + super().start() + print("Start counting: delay = 1s") + + def run(self) -> None: + for i in range(10): + print(f"Counter 1: {i}") + time.sleep(1) + + +class Counter3(Thread): + """Thread counting with 3s delay.""" + + def start(self) -> None: + super().start() + print("Start counting: delay = 3s") + + def run(self) -> None: + for i in range(3): + print(f"Counter 3: {i}") + time.sleep(3) + + +def main(): + counter1_thread = Counter1() + counter3_thread = Counter3() + print(f"{counter1_thread.is_alive() = }") + + # Start both threads: both code will run in parallel + counter1_thread.start() + counter3_thread.start() + print(f"{counter1_thread.is_alive() = }") + + print("Main thread: sleeping") + time.sleep(12) + + # Make sure each thread has finished, or wait until they are finished + print("Main thread: waiting for all threads") + counter1_thread.join() + counter3_thread.join() + print(f"{counter1_thread.is_alive() = }") + + +if __name__ == "__main__": + main() diff --git a/TP3/vectors.py b/TP3/vectors.py new file mode 100644 index 0000000..1c2f41d --- /dev/null +++ b/TP3/vectors.py @@ -0,0 +1,78 @@ +"""Manipulation of 2D-vectors.""" + +from __future__ import annotations + + +class Point: + def __init__(self, x: float, y: float): + self.x=x + self.y=y + def __str__(self): + return f"Point = ({self.x},{self.y})" + + + +class Vector: + def __init__(self,A:Point,B:Point): + self.x=B.x-A.x + self.y=B.y-A.y + def produit_scalaire(self,other): + prod=self.x*other.x + self.y*other.y + return prod + def __str__(self): + return f"Vecteur = ({self.x},{self.y})" + def __add__(self,other): + return (self.x+other.x,self.y+other.y) + def __sub__(self,other): + return (self.x-other.x,self.y-other.y) + + + +def main(): + origin = Point(0, 0) + point_A = Point(-2, -1) + point_B = Point(3, 7) + + print(f"Point O: x={origin.x} y={origin.y}") + print(f"Point A: x={point_A.x} y={point_A.y}") + print(point_A) + + + vector_OA = Vector(origin, point_A) + vector_AB = Vector(point_A, point_B) + + print(f"Vector OA: dx={vector_OA.x} dy={vector_OA.y}") + print(f"Vector AB: dx={vector_AB.x} dy={vector_AB.y}") + print(vector_AB) + + + +def main_2(): + v = Vector(1, 2) + v2 = Vector(1, 0) + print(v.dot_prod(v2)) + print(v2.dot_prod(v)) + + +def main_3(): + v = Vector(1, 2) + v2 = Vector(1, 0) + print(-v) + print(-(-v)) + print(v + v2) + print(v - v2) + print(v * 3) + print(v2 * -10) + + +def main_4(): + point_B = Point(3, 7) + vector_OB = Vector.from_origin(point_B) + print(vector_OB) + + +if __name__ == "__main__": + main() + # main_2() + # main_3() + # main_4() \ No newline at end of file