├── exercices ├── p3c2_films │ ├── __init__.py │ ├── films │ │ ├── __init__.py │ │ ├── data.py │ │ ├── library.py │ │ ├── friend.py │ │ └── film.py │ └── main.py ├── p3c1_solution │ ├── contact │ │ ├── __init__.py │ │ ├── abstract.py │ │ ├── user.py │ │ ├── helpers.py │ │ ├── owlcontact.py │ │ └── textcontact.py │ └── main.py ├── p1c3_toolbox.py ├── p1c4_smart_plug.py ├── p3c3_exceptions.py ├── p3c1_contact.py ├── p2c2_forum.py ├── p2c3_forum.py ├── p1c4_toolbox.py ├── p2c4_forum.py └── p2c5_forum.py ├── .gitignore └── README.md /exercices/p3c2_films/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /exercices/p3c1_solution/contact/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .* 3 | __* 4 | screencasts 5 | !__init__.py 6 | -------------------------------------------------------------------------------- /exercices/p3c2_films/films/__init__.py: -------------------------------------------------------------------------------- 1 | """Package comprenant le code de l'application.""" 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 7150626-Apprenez-la-programmation-orientee-objet-avec-Python 2 | 3 | Vous trouverez les différents exercices du cours dans le repertoire `exercices`. :) 4 | -------------------------------------------------------------------------------- /exercices/p3c1_solution/contact/abstract.py: -------------------------------------------------------------------------------- 1 | """Définit la classe de contact abstraite.""" 2 | 3 | from abc import ABC, abstractmethod 4 | 5 | 6 | class ContactSystem(ABC): 7 | """Classe abstraite utilisée pour envoyer un message à un utilisateur.""" 8 | 9 | @abstractmethod 10 | def send(self, message): 11 | """Toutes les sous-classes de COntactSystem doivent implémenter send.""" 12 | pass 13 | 14 | -------------------------------------------------------------------------------- /exercices/p3c1_solution/contact/user.py: -------------------------------------------------------------------------------- 1 | """Définit l'utilisateur.""" 2 | 3 | 4 | class User: 5 | """Un utilisateur.""" 6 | 7 | def __init__(self, name, contact_method): 8 | """Initialise un nom et une methode de contact.""" 9 | self.name = name 10 | self.contact_method = contact_method 11 | 12 | def send(self, message): 13 | """Envoit un message.""" 14 | self.contact_method.send(message) 15 | -------------------------------------------------------------------------------- /exercices/p3c2_films/films/data.py: -------------------------------------------------------------------------------- 1 | """Les données brutes.""" 2 | 3 | films = [ 4 | ("Blade Runner (1982)", "vhf"), 5 | ("Alien : Le 8ème Passager (1979)", "vhf"), 6 | ("2001 : L'Odyssée de l'espace (1968)", "VhF"), 7 | ("Matrix (1999)", "DVD"), 8 | ("Interstellar (2014)", "dvD"), 9 | ("L'Empire contre-attaque (1980)", "vhf"), 10 | ("Retour vers le futur (1985)", "vhf"), 11 | ("La Guerre des Étoiles (1977)", "vhf"), 12 | ("L'Armée des 12 singes (1995)", "dVd"), 13 | ("Terminator 2 : Le Jugement dernier (1991)", "DVD"), 14 | ] 15 | 16 | friends = [ 17 | ("Paul", "Blade Runner"), 18 | ("Lucie",), 19 | ("Zoé", "Terminator 2 : Le Jugement dernier"), 20 | ] 21 | -------------------------------------------------------------------------------- /exercices/p3c1_solution/contact/helpers.py: -------------------------------------------------------------------------------- 1 | """Donne des méthodes d'aides pour l'utilisation du système de contact.""" 2 | 3 | 4 | def verify_adress(address): 5 | """Fausse fonction qui retourne True.""" 6 | return True 7 | 8 | 9 | def validate_phone(phone_number): 10 | """Retourne True par défaut.""" 11 | return True 12 | 13 | 14 | def send_mass_messages(message, user_list): 15 | """Envoi des messages en masse. 16 | 17 | Utilise la méthode de message de chaque utilisateur.""" 18 | for user in user_list: 19 | mail_merge = {"name": user.name, "contact_info": user.contact_method} 20 | customised_message = message.format(**mail_merge) 21 | user.send(customised_message) 22 | -------------------------------------------------------------------------------- /exercices/p3c1_solution/contact/owlcontact.py: -------------------------------------------------------------------------------- 1 | """Définit le contact par chouette.""" 2 | 3 | from contact.abstract import ContactSystem 4 | from contact.helpers import verify_adress 5 | 6 | 7 | class OwlContactSystem(ContactSystem): 8 | """Envoi un message en utilisant une chouette ! 🧙‍♂️""" 9 | 10 | def __init__(self, address): 11 | """Initialise l'adresse.""" 12 | verify_adress(address) 13 | self.address = address 14 | self.owl = "Hedwige" 15 | super().__init__() 16 | 17 | def send(self, message): 18 | """Envoi le message.""" 19 | print(f'Envoi du message "{message}" par chouette {self.owl}') 20 | 21 | def __str__(self): 22 | """Représentation.""" 23 | return f"L'addresse est '{self.address}'" 24 | -------------------------------------------------------------------------------- /exercices/p3c1_solution/main.py: -------------------------------------------------------------------------------- 1 | """Point d'entrée.""" 2 | 3 | from contact.user import User 4 | from contact.owlcontact import OwlContactSystem 5 | from contact.textcontact import TextContactSystem 6 | from contact.helpers import send_mass_messages 7 | 8 | 9 | def main(): 10 | """Main function.""" 11 | alice = User("Alice", TextContactSystem("0102030405")) 12 | bob = User("Bob", OwlContactSystem("4 Privet Drive")) 13 | 14 | user_list = [alice, bob] 15 | send_mass_messages("Hello {name}, Comment vas-tu?", user_list) 16 | send_mass_messages( 17 | "Salut {name}. Tes informations de contact sont-elles corrects?" 18 | " Nous avons celles-ci: {contact_info}.", 19 | user_list, 20 | ) 21 | 22 | 23 | if __name__ == "__main__": 24 | main() 25 | -------------------------------------------------------------------------------- /exercices/p3c1_solution/contact/textcontact.py: -------------------------------------------------------------------------------- 1 | """Définit le contact par téléphone.""" 2 | 3 | from contact.abstract import ContactSystem 4 | from contact.helpers import validate_phone 5 | 6 | 7 | class TextContactSystem(ContactSystem): 8 | """Envoi un message à l'utilisateur par SMS.""" 9 | 10 | def __init__(self, phone_number): 11 | """Initialise le numéro de téléphone.""" 12 | super().__init__() 13 | validate_phone(phone_number) 14 | self.phone_number = phone_number 15 | 16 | def send(self, message): 17 | """Envoi le message.""" 18 | print(f'Envoi du message "{message}" au numéro {self.phone_number}') 19 | 20 | def __str__(self): 21 | """Représentation lisible.""" 22 | return f"Le numéro de téléphone est {self.phone_number}" 23 | -------------------------------------------------------------------------------- /exercices/p3c2_films/main.py: -------------------------------------------------------------------------------- 1 | """Point d'entrée.""" 2 | 3 | # l'utilisation de pprint permet de mieux afficher les conteneurs. 4 | from pprint import pprint 5 | 6 | from films.friend import FriendCleaner 7 | from films.library import Library 8 | 9 | 10 | def main(): 11 | """Code client.""" 12 | library = Library() 13 | 14 | films = library.films 15 | friends = FriendCleaner().list_from_data(library) 16 | 17 | print("Tous mes films:") 18 | pprint(films) 19 | print() 20 | print("Tous mes amis:") 21 | pprint(friends) 22 | print() 23 | 24 | library.sort_by_type() 25 | print("Mes films triés par type:") 26 | pprint(films) 27 | print() 28 | 29 | film = library.get_random_choice() 30 | print(f"Film récupéré au hasard: {film}") 31 | print() 32 | 33 | films_lent = library.get_films_lent() 34 | print("J'ai prêté ces films:") 35 | pprint(films_lent) 36 | print() 37 | 38 | for film in films_lent: 39 | print(f"Le film '{film}' est chez", film.where) 40 | 41 | 42 | if __name__ == "__main__": 43 | main() 44 | -------------------------------------------------------------------------------- /exercices/p1c3_toolbox.py: -------------------------------------------------------------------------------- 1 | """Définit des classes d'outils.""" 2 | 3 | 4 | class ToolBox: 5 | """Boite à outils.""" 6 | 7 | def __init__(self): 8 | """Initialise les outils.""" 9 | self.tools = [] 10 | 11 | def add_tool(self, tool): 12 | """Ajoute un outil.""" 13 | pass 14 | 15 | def remove_tool(self, tool): 16 | """Enleve un outil.""" 17 | pass 18 | 19 | 20 | class Screwdriver: 21 | """Tournevis.""" 22 | 23 | def __init__(self, size): 24 | """Initialise la taille.""" 25 | self.size = size 26 | 27 | def tighten(self, screw): 28 | """Serrer une vis.""" 29 | pass 30 | 31 | def loosen(self, screw): 32 | """Desserre une vis.""" 33 | pass 34 | 35 | 36 | class Hammer: 37 | """Marteau.""" 38 | 39 | def __init__(self, color="red"): 40 | """Initialise la couleur.""" 41 | self.color = color 42 | 43 | def paint(self, color): 44 | """Paint le marteau.""" 45 | pass 46 | 47 | def hammer_in(self, nail): 48 | """Enfonce un clou.""" 49 | pass 50 | 51 | def remove(self, nail): 52 | """Enleve un clou.""" 53 | pass 54 | -------------------------------------------------------------------------------- /exercices/p1c4_smart_plug.py: -------------------------------------------------------------------------------- 1 | """Prise connectée.""" 2 | 3 | 4 | class SmartPlug: 5 | """Prise intelligente : connecte les appareils.""" 6 | 7 | def __init__(self): 8 | """Initialise la liste d'appareils.""" 9 | self.devices = [] 10 | 11 | def connect(self, device): 12 | """Connecte un appareil à la prise.""" 13 | self.devices.append(device) 14 | 15 | def display_connected_devices(self): 16 | """Affiche les appareils connectés.""" 17 | print("Affichage des appareils connectés...") 18 | if not self.devices: 19 | print("Aucun appareil n'est connecté !") 20 | return 21 | for device in self.devices: 22 | print(f"-> {device.name}") 23 | print("Fin de l'affichage.") 24 | 25 | 26 | class Device: 27 | """Appareil électronique à connecter.""" 28 | 29 | def __init__(self, name): 30 | """Initialise le nom.""" 31 | self.name = name 32 | 33 | 34 | # On instancie les composants 35 | plug = SmartPlug() 36 | pc = Device("pc") 37 | screen = Device("écran") 38 | 39 | # On connecte les appareils à la prise 40 | plug.connect(pc) 41 | plug.connect(screen) 42 | 43 | # On vérifie la connexion ;) 44 | plug.display_connected_devices() 45 | -------------------------------------------------------------------------------- /exercices/p3c3_exceptions.py: -------------------------------------------------------------------------------- 1 | class User: 2 | """Un utilisateur.""" 3 | 4 | def __init__(self, username, password): 5 | """Initialise le nom et le mot de passe.""" 6 | if len(username) < 2: 7 | raise UsernameTooShortException() 8 | if len(password) < 10: 9 | raise PasswordTooShortException() 10 | 11 | self.username = username 12 | self.password = password 13 | 14 | 15 | class UsernameTooShortException(Exception): 16 | """Erreur sur le nom d'utilisateur.""" 17 | 18 | def __init__(self, msg="", *args, **kwargs): 19 | """Init le message.""" 20 | msg = msg or "Le nom d'utilisateur est trop court !" 21 | super().__init__(msg, *args, **kwargs) 22 | 23 | 24 | class PasswordTooShortException(Exception): 25 | """Erreur sur le mot de passe.""" 26 | 27 | def __init__(self, msg="", *args, **kwargs): 28 | """Init le message.""" 29 | msg = msg or "Le mot de passe est trop court !" 30 | super().__init__(msg, *args, **kwargs) 31 | 32 | 33 | if __name__ == "__main__": 34 | user = User("John", "supersecret") 35 | try: 36 | user = User("t", "supersecret") 37 | except UsernameTooShortException: 38 | print("L'exception sur le nom d'utilisateur a été levée.") 39 | 40 | try: 41 | user = User("John", "t") 42 | except PasswordTooShortException: 43 | print("L'exception sur le mot de passe a été levée.") 44 | -------------------------------------------------------------------------------- /exercices/p3c2_films/films/library.py: -------------------------------------------------------------------------------- 1 | """Définit la bibliothèque virtuelle.""" 2 | 3 | import random 4 | 5 | from .film import FilmCleaner 6 | from .data import films 7 | 8 | 9 | class Library: 10 | """Bibliothèque de films.""" 11 | 12 | def __init__(self): 13 | """Initialise les films.""" 14 | self.films = [] 15 | for film_data in films: 16 | film = FilmCleaner(film_data).generate() 17 | film.where = self 18 | self.films.append(film) 19 | 20 | self.sort_by_date_and_name() 21 | 22 | def sort_by_date_and_name(self): 23 | """Tri les films par date et par nom.""" 24 | self.films.sort(key=lambda film: (film.date, film.name)) 25 | 26 | def sort_by_type(self): 27 | """Tri les films par type.""" 28 | self.films.sort(key=lambda film: film.type) 29 | 30 | def get_random_choice(self): 31 | """Retourne un film au hasard.""" 32 | return random.choice(self.films) 33 | 34 | def get_films_lent(self): 35 | """retourne la liste des films prêtés. 36 | 37 | Note: On pourrait aussi utiliser une liste de compréhension ici. 38 | """ 39 | films_lent = [] 40 | for film in self.films: 41 | if film.where is not self: # le film n'est pas dans la bibliothèque 42 | films_lent.append(film) 43 | return films_lent 44 | 45 | def find_by_name(self, name): 46 | """Retourne un film si le nom correspond, sinon None.""" 47 | for film in self.films: 48 | if name == film.name: 49 | return film 50 | return None 51 | -------------------------------------------------------------------------------- /exercices/p3c2_films/films/friend.py: -------------------------------------------------------------------------------- 1 | """Définit les amis.""" 2 | 3 | from .data import friends 4 | 5 | 6 | class Friend: 7 | """Ami.""" 8 | 9 | def __init__(self, name, film=None): 10 | """Initialise le nom, et un film prêté si c'est le cas.""" 11 | self.name = name 12 | self.film = film 13 | if film: 14 | film.where = self 15 | 16 | def __str__(self): 17 | return f"{self.name}" 18 | 19 | def __repr__(self): 20 | return self.__str__() 21 | 22 | 23 | class FriendCleaner: 24 | """Génère un ami d'après les données brutes.""" 25 | 26 | NAME_INDEX = 0 27 | FILM_INDEX = 1 28 | 29 | def __init__(self): 30 | """Initialise les données d'amis.""" 31 | self.friends = friends 32 | 33 | def generate(self, data, library): 34 | """Retourne un ami à partir des données brutes. 35 | 36 | Attention ici l'exercice consistait à utiliser 37 | de vrais objets films et pas juste le nom du film ! 38 | """ 39 | name = data[self.NAME_INDEX] 40 | if len(data) > 1: 41 | film_name = data[self.FILM_INDEX] 42 | film = library.find_by_name(film_name) 43 | else: 44 | film = None 45 | 46 | return Friend(name, film) 47 | 48 | def list_from_data(self, library): 49 | """Retourne une liste d'amis à partir des données brutes. 50 | 51 | Attrs: 52 | - library (Library) : une instance de bibliothèque de films. 53 | 54 | Note: On pourrait aussi utiliser une liste de compréhension ici. 55 | """ 56 | result = [] 57 | for data in self.friends: 58 | friend = self.generate(data, library) 59 | result.append(friend) 60 | return result 61 | -------------------------------------------------------------------------------- /exercices/p3c2_films/films/film.py: -------------------------------------------------------------------------------- 1 | """Définit les films. 2 | 3 | Note: l'utilisation de l'héritage ici est surtout à but éducatif. 4 | """ 5 | 6 | 7 | class Film: 8 | """Film.""" 9 | 10 | def __init__(self, name, date): 11 | """Initialise le nom et la date. 12 | 13 | L'attribut "where" permet de savoir où est un film. 14 | """ 15 | self.name = name 16 | self.date = date 17 | self.where = None 18 | 19 | def __str__(self): 20 | return f"{self.name} ({self.date})" 21 | 22 | def __repr__(self) -> str: 23 | return str(self) 24 | 25 | 26 | class FilmVHF(Film): 27 | """Film VHF.""" 28 | 29 | type = "vhf" 30 | 31 | def __init__(self, name, date): 32 | """Initialise le type.""" 33 | super().__init__(name, date) 34 | self.magnetic_tape = True 35 | 36 | 37 | class FilmDVD(Film): 38 | """Film DVD.""" 39 | 40 | type = "dvd" 41 | 42 | def __init__(self, name, date): 43 | """Initialise le type.""" 44 | super().__init__(name, date) 45 | self.mega_octets = 4700 46 | 47 | 48 | class FilmCleaner: 49 | """Génère un film à partir de données brutes.""" 50 | 51 | NAME_AND_DATE_INDEX = 0 52 | TYPE_INDEX = 1 53 | 54 | def __init__(self, film_data): 55 | self.film_data = film_data 56 | 57 | def generate(self): 58 | """Génère le film.""" 59 | name = self.generate_name() 60 | date = self.generate_date() 61 | type = self.generate_type() 62 | 63 | # ici on itère sur un tuple de classes (et non d'instances) ! 64 | for Film in (FilmVHF, FilmDVD): 65 | # on vérifie le type du film par rapport au type de chaque classe 66 | if type == Film.type: 67 | # et on retourne un instance de la classe choisie. 68 | return Film(name, date) 69 | 70 | def generate_name(self): 71 | """Génère le nom.""" 72 | name_date = self.film_data[self.NAME_AND_DATE_INDEX] 73 | return name_date[: name_date.index("(")].strip() 74 | 75 | def generate_date(self): 76 | """Génère la date.""" 77 | name_date = self.film_data[self.NAME_AND_DATE_INDEX] 78 | date_with_parenthesis = name_date[name_date.index("(") :] 79 | date_letters = date_with_parenthesis.replace("(", "").replace(")", "") 80 | return int(date_letters) 81 | 82 | def generate_type(self): 83 | """Génère le type.""" 84 | return self.film_data[self.TYPE_INDEX].lower() 85 | -------------------------------------------------------------------------------- /exercices/p3c1_contact.py: -------------------------------------------------------------------------------- 1 | """Contacts. 2 | 3 | Séparez le programme en plusieurs modules et packages, 4 | en ajoutant les fichiers __init__.py et les imports si necessaire. 5 | 6 | Vérifiez que le programme s'éxecute correctement en lancant main.py depuis la racine 7 | du projet. 8 | """ 9 | 10 | from abc import ABC, abstractmethod 11 | 12 | 13 | class User: 14 | """Un utilisateur.""" 15 | 16 | def __init__(self, name, contact_method): 17 | """Initialise un nom et une methode de contact.""" 18 | self.name = name 19 | self.contact_method = contact_method 20 | 21 | def send(self, message): 22 | """Envoit un message.""" 23 | self.contact_method.send(message) 24 | 25 | 26 | class ContactSystem(ABC): 27 | """Classe abstraite utilisée pour envoyer un message à un utilisateur.""" 28 | 29 | @abstractmethod 30 | def send(self, message): 31 | """Toutes les sous-classes de ContactSystem doivent implémenter send.""" 32 | pass 33 | 34 | 35 | class TextContactSystem(ContactSystem): 36 | """Envoi un message à l'utilisateur par SMS.""" 37 | 38 | def __init__(self, phone_number): 39 | """Initialise le numéro de téléphone.""" 40 | super().__init__() 41 | validate_phone(phone_number) 42 | self.phone_number = phone_number 43 | 44 | def send(self, message): 45 | """Envoi le message.""" 46 | print(f'Envoi du message "{message}" au numéro {self.phone_number}') 47 | 48 | def __str__(self): 49 | """Représentation lisible.""" 50 | return f"Le numéro de téléphone est {self.phone_number}" 51 | 52 | 53 | class OwlContactSystem(ContactSystem): 54 | """Envoi un message en utilisant une chouette ! 🧙‍♂️""" 55 | 56 | def __init__(self, address): 57 | """Initialise l'addresse.""" 58 | varify_address(address) 59 | self.address = address 60 | self.owl = "Hedwige" 61 | super().__init__() 62 | 63 | def send(self, message): 64 | """Envoi le message.""" 65 | print(f'Envoi du message "{message}" par chouette {self.owl}') 66 | 67 | def __str__(self): 68 | """Représentation.""" 69 | return f"L'addresse est '{self.address}'" 70 | 71 | 72 | def varify_address(address): 73 | """Fausse fonction qui retourne True.""" 74 | return True 75 | 76 | 77 | def validate_phone(phone_number): 78 | """Retourne True par défaut.""" 79 | return True 80 | 81 | 82 | def send_mass_messages(message, user_list): 83 | """Envoi des messages en masse. 84 | 85 | Utilise la méthode de message de chaque utilisateur.""" 86 | for user in user_list: 87 | mail_merge = {"name": user.name, "contact_info": user.contact_method} 88 | customised_message = message.format(**mail_merge) 89 | user.send(customised_message) 90 | 91 | 92 | # Our main program. 93 | alice = User("Alice", TextContactSystem("0102030405")) 94 | bob = User("Bob", OwlContactSystem("4 Privet Drive")) 95 | 96 | user_list = [alice, bob] 97 | send_mass_messages("Hello {name}, Comment vas-tu?", user_list) 98 | send_mass_messages( 99 | "Salut {name}. Tes informations de contact sont-elles corrects?" 100 | " Nous avons celles-ci: {contact_info}.", 101 | user_list, 102 | ) 103 | -------------------------------------------------------------------------------- /exercices/p2c2_forum.py: -------------------------------------------------------------------------------- 1 | """Définit les classes propres à notre forum. ;)""" 2 | 3 | 4 | class File: 5 | """Fichier.""" 6 | 7 | def __init__(self, name, size): 8 | """Initialise le nom et la taille.""" 9 | self.name = name 10 | self.size = size 11 | 12 | def display(self): 13 | """Affiche le fichier.""" 14 | print(f"Fichier '{self.name}'.") 15 | 16 | 17 | class ImageFile(File): 18 | """Fichier image. 19 | 20 | Pas plus à ajouter pour l'instant ! 21 | """ 22 | 23 | pass 24 | 25 | 26 | class User: 27 | """Utilisateur.""" 28 | 29 | def __init__(self, username, password): 30 | """Initialise le nom d'utilisateur et le mot de passe.""" 31 | self.username = username 32 | self.password = password 33 | 34 | def login(self): 35 | """Connecte l'utilisateur.""" 36 | print(f"L'utilisateur {self.username} est connecté.") 37 | 38 | def post(self, thread, content, file=None): 39 | """Poste un message dans un fil de discussion.""" 40 | if file: 41 | post = FilePost(self, "aujourd'hui", content, file) 42 | else: 43 | post = Post(user=self, time_posted="aujourd'hui", content=content) 44 | thread.add_post(post) 45 | return post 46 | 47 | def make_thread(self, title, content): 48 | """Créé un nouveau fil de discussion.""" 49 | post = Post(self, "aujourd'hui", content) 50 | return Thread(title, "aujourd'hui", post) 51 | 52 | def __str__(self): 53 | """représentation de l'utilisateur.""" 54 | return self.username 55 | 56 | 57 | class Moderator(User): 58 | """Utilisateur modérateur.""" 59 | 60 | def edit(self, post, content): 61 | """Modifie un message.""" 62 | post.content = content 63 | 64 | def delete(self, thread, post): 65 | """Supprime un message.""" 66 | index = thread.posts.index(post) 67 | del thread.posts[index] 68 | 69 | 70 | class Post: 71 | """Message.""" 72 | 73 | def __init__(self, user, time_posted, content): 74 | """Initialise l'utilisateur, la date et le contenu.""" 75 | self.user = user 76 | self.time_posted = time_posted 77 | self.content = content 78 | 79 | def display(self): 80 | """Affiche le message.""" 81 | print(f"Message posté par {self.user} le {self.time_posted}:") 82 | print(self.content) 83 | 84 | 85 | class FilePost(Post): 86 | """Message comportant un fichier.""" 87 | 88 | def __init__(self, user, time_posted, content, file): 89 | """Initialise le fichier.""" 90 | self.user = user 91 | self.time_posted = time_posted 92 | self.content = content 93 | self.file = file 94 | 95 | def display(self): 96 | """Affiche le contenu et le fichier.""" 97 | super().display() 98 | print("pièce jointe:") 99 | self.file.display() 100 | 101 | 102 | class Thread: 103 | """Fil de discussions.""" 104 | 105 | def __init__(self, title, time_posted, post): 106 | """Initialise le titre, la date et les posts. 107 | 108 | Attention ici: on commence par un seul post, celui du sujet. 109 | Les réponses à ce post ne pourrons s'ajouter qu'ultérieurement. 110 | En effet, on ne créé pas directement un nouveau fil avec des réponses. ;) 111 | """ 112 | self.title = title 113 | self.time_posted = time_posted 114 | self.posts = [post] 115 | 116 | def display(self): 117 | """Affiche le fil de discussion.""" 118 | print("----- THREAD -----") 119 | print(f"titre: {self.title}, date: {self.time_posted}") 120 | print() 121 | for post in self.posts: 122 | post.display() 123 | print() 124 | print("------------------") 125 | 126 | def add_post(self, post): 127 | """Ajoute un post.""" 128 | self.posts.append(post) 129 | -------------------------------------------------------------------------------- /exercices/p2c3_forum.py: -------------------------------------------------------------------------------- 1 | """Définit les classes propres à notre forum. ;)""" 2 | 3 | from abc import ABC 4 | 5 | 6 | class File(ABC): 7 | """Fichier.""" 8 | 9 | def __init__(self, name, size): 10 | """Initialise le nom et la taille.""" 11 | self.name = name 12 | self.size = size 13 | 14 | def display(self): 15 | """Affiche le fichier.""" 16 | pass 17 | 18 | 19 | class ImageFile(File): 20 | """Fichier image.""" 21 | 22 | def display(self): 23 | """Affiche l'image.""" 24 | print(f"Fichier image '{self.name}'.") 25 | 26 | 27 | class User: 28 | """Utilisateur.""" 29 | 30 | def __init__(self, username, password): 31 | """Initialise le nom d'utilisateur et le mot de passe.""" 32 | self.username = username 33 | self.password = password 34 | 35 | def login(self): 36 | """Connecte l'utilisateur.""" 37 | print(f"L'utilisateur {self.username} est connecté.") 38 | 39 | def post(self, thread, content, file=None): 40 | """Poste un message dans un fil de discussion.""" 41 | if file: 42 | post = FilePost(self, "aujourd'hui", content, file) 43 | else: 44 | post = Post(user=self, time_posted="aujourd'hui", content=content) 45 | thread.add_post(post) 46 | return post 47 | 48 | def make_thread(self, title, content): 49 | """Créé un nouveau fil de discussion.""" 50 | post = Post(self, "aujourd'hui", content) 51 | return Thread(title, "aujourd'hui", post) 52 | 53 | def __str__(self): 54 | """représentation de l'utilisateur.""" 55 | return self.username 56 | 57 | 58 | class Moderator(User): 59 | """Utilisateur modérateur.""" 60 | 61 | def edit(self, post, content): 62 | """Modifie un message.""" 63 | post.content = content 64 | 65 | def delete(self, thread, post): 66 | """Supprime un message.""" 67 | index = thread.posts.index(post) 68 | del thread.posts[index] 69 | 70 | 71 | class Post: 72 | """Message.""" 73 | 74 | def __init__(self, user, time_posted, content): 75 | """Initialise l'utilisateur, la date et le contenu.""" 76 | self.user = user 77 | self.time_posted = time_posted 78 | self.content = content 79 | 80 | def display(self): 81 | """Affiche le message.""" 82 | print(f"Message posté par {self.user} le {self.time_posted}:") 83 | print(self.content) 84 | 85 | 86 | class FilePost(Post): 87 | """Message comportant un fichier.""" 88 | 89 | def __init__(self, user, time_posted, content, file): 90 | """Initialise le fichier.""" 91 | super().__init__(user, time_posted, content) 92 | self.file = file 93 | 94 | def display(self): 95 | """Affiche le contenu et le fichier.""" 96 | super().display() 97 | print("pièce jointe:") 98 | self.file.display() 99 | 100 | 101 | class Thread: 102 | """Fil de discussions.""" 103 | 104 | def __init__(self, title, time_posted, post): 105 | """Initialise le titre, la date et les posts. 106 | 107 | Attention ici: on commence par un seul post, celui du sujet. 108 | Les réponses à ce post ne pourrons s'ajouter qu'ultérieurement. 109 | En effet, on ne créé pas directement un nouveau fil avec des réponses. ;) 110 | """ 111 | self.title = title 112 | self.time_posted = time_posted 113 | self.posts = [post] 114 | 115 | def display(self): 116 | """Affiche le fil de discussion.""" 117 | print("----- THREAD -----") 118 | print(f"titre: {self.title}, date: {self.time_posted}") 119 | print() 120 | for post in self.posts: 121 | post.display() 122 | print() 123 | print("------------------") 124 | 125 | def add_post(self, post): 126 | """Ajoute un post.""" 127 | self.posts.append(post) 128 | -------------------------------------------------------------------------------- /exercices/p1c4_toolbox.py: -------------------------------------------------------------------------------- 1 | """Ici, nous allons serrer des vis et taper sur des clous!""" 2 | 3 | 4 | class ToolBox: 5 | """Boite à outils.""" 6 | 7 | def __init__(self): 8 | """Initialise les outils.""" 9 | self.tools = [] 10 | 11 | def add_tool(self, tool): 12 | """Ajoute un outil.""" 13 | self.tools.append(tool) 14 | 15 | def remove_tool(self, tool): 16 | """Enleve un outil.""" 17 | index = self.tools.index(tool) 18 | del self.tools[index] 19 | 20 | 21 | class Screwdriver: 22 | """Tournevis.""" 23 | 24 | def __init__(self, size=3): 25 | """Initialise la taille.""" 26 | self.size = size 27 | 28 | def tighten(self, screw): 29 | """Serrer une vis.""" 30 | screw.tighten() 31 | 32 | def loosen(self, screw): 33 | """Desserre une vis.""" 34 | screw.loosen() 35 | 36 | def __repr__(self): 37 | """Représentation de l'objet.""" 38 | return f"Tournevis de taille {self.size}" 39 | 40 | 41 | class Hammer: 42 | """Marteau.""" 43 | 44 | def __init__(self, color="red"): 45 | """Initialise la couleur.""" 46 | self.color = color 47 | 48 | def paint(self, color): 49 | """Paint le marteau.""" 50 | self.color = color 51 | 52 | def hammer_in(self, nail): 53 | """Enfonce un clou.""" 54 | nail.nail_in() 55 | 56 | def remove(self, nail): 57 | """Enleve un clou.""" 58 | nail.remove() 59 | 60 | def __repr__(self): 61 | """Représentation de l'objet.""" 62 | return f"Marteau de couleur {self.color}" 63 | 64 | 65 | class Screw: 66 | """Vis.""" 67 | 68 | MAX_TIGHTNESS = 5 69 | 70 | def __init__(self): 71 | """Initialise son degré de serrage.""" 72 | self.tightness = 0 73 | 74 | def loosen(self): 75 | """Déserre le vis.""" 76 | if self.tightness > 0: 77 | self.tightness -= 1 78 | 79 | def tighten(self): 80 | """Serre le vis.""" 81 | if self.tightness < self.MAX_TIGHTNESS: 82 | self.tightness += 1 83 | 84 | def __str__(self): 85 | """Retourne une forme lisible de l'objet.""" 86 | return "Vis avec un serrage de {}".format(self.tightness) 87 | 88 | 89 | class Nail: 90 | """Clou.""" 91 | 92 | def __init__(self): 93 | """Initialise son statut "dans le mur".""" 94 | self.in_wall = False 95 | 96 | def nail_in(self): 97 | """Enfonce le clou dans un mur.""" 98 | if not self.in_wall: 99 | self.in_wall = True 100 | 101 | def remove(self): 102 | """Enlève le clou du mur.""" 103 | if self.in_wall: 104 | self.in_wall = False 105 | 106 | def __str__(self): 107 | """Retourne une forme lisible de l'objet.""" 108 | wall_state = "dans le mur" if self.in_wall else "hors du mur" 109 | return f"Clou {wall_state}." 110 | 111 | 112 | # Instanciez une boîte à outils, un tournevis, et un marteau. 113 | hammer = Hammer() 114 | screwdriver = Screwdriver() 115 | toolbox = ToolBox() 116 | 117 | # Placez le marteau et le tournevis dans la boîte à outils. 118 | toolbox.add_tool(hammer) 119 | toolbox.add_tool(screwdriver) 120 | 121 | # Instanciez une vis, et serrez-la avec le tournevis. 122 | # Affichez la vis avant après avoir été serrée. 123 | screw = Screw() 124 | print(screw) 125 | screwdriver.tighten(screw) 126 | print(screw) 127 | 128 | # Instanciez un clou, puis enfoncez-le avec le marteau. 129 | # Affichez le clou avant et après avoir été enfoncé. 130 | nail = Nail() 131 | print(nail) 132 | hammer.hammer_in(nail) 133 | print(nail) 134 | 135 | 136 | # -------------------------------------------------------------- 137 | # Que pouvez-vous faire d’autre avec ces classes et ces objets ? 138 | 139 | # enlever un outil 140 | print("outils dans la boîte:", toolbox.tools) 141 | toolbox.remove_tool(hammer) 142 | print("on a enlevé le marteau") 143 | print("outils dans la boîte:", toolbox.tools) 144 | 145 | # désserrer la vis 146 | screwdriver.loosen(screw) 147 | print(screw) 148 | 149 | # enlever le clou 150 | hammer.remove(nail) 151 | print(nail) 152 | 153 | # repeindre le marteau 154 | hammer.paint("yellow") 155 | print(hammer) 156 | -------------------------------------------------------------------------------- /exercices/p2c4_forum.py: -------------------------------------------------------------------------------- 1 | """Définit les classes propres à notre forum. ;)""" 2 | 3 | from abc import ABC 4 | 5 | 6 | class File(ABC): 7 | """Fichier.""" 8 | 9 | def __init__(self, name, size): 10 | """Initialise le nom et la taille.""" 11 | self.name = name 12 | self.size = size 13 | 14 | def display(self): 15 | """Affiche le fichier.""" 16 | pass 17 | 18 | 19 | class ImageFile(File): 20 | """Fichier image.""" 21 | 22 | def display(self): 23 | """Affiche l'image.""" 24 | print(f"Fichier image '{self.name}'.") 25 | 26 | 27 | class GifImageFile(ImageFile): 28 | """Fichier image Gif.""" 29 | 30 | def display(self): 31 | """Affiche l'image.""" 32 | super().display() 33 | print("L'image est de type 'Gif'.") 34 | 35 | 36 | class PNGImageFile(ImageFile): 37 | """Fichier image PNG.""" 38 | 39 | def display(self): 40 | """Affiche l'image.""" 41 | super().display() 42 | print("L'image est de type 'PNG'.") 43 | 44 | 45 | class User: 46 | """Utilisateur.""" 47 | 48 | def __init__(self, username, password): 49 | """Initialise le nom d'utilisateur et le mot de passe.""" 50 | self.username = username 51 | self.password = password 52 | 53 | def login(self): 54 | """Connecte l'utilisateur.""" 55 | print(f"L'utilisateur {self.username} est connecté.") 56 | 57 | def post(self, thread, content, file=None): 58 | """Poste un message dans un fil de discussion.""" 59 | if file: 60 | post = FilePost(self, "aujourd'hui", content, file) 61 | else: 62 | post = Post(user=self, time_posted="aujourd'hui", content=content) 63 | thread.add_post(post) 64 | return post 65 | 66 | def make_thread(self, title, content): 67 | """Créé un nouveau fil de discussion.""" 68 | post = Post(self, "aujourd'hui", content) 69 | return Thread(title, "aujourd'hui", post) 70 | 71 | def __str__(self): 72 | """représentation de l'utilisateur.""" 73 | return self.username 74 | 75 | 76 | class Moderator(User): 77 | """Utilisateur modérateur.""" 78 | 79 | def edit(self, post, content): 80 | """Modifie un message.""" 81 | post.content = content 82 | 83 | def delete(self, thread, post): 84 | """Supprime un message.""" 85 | index = thread.posts.index(post) 86 | del thread.posts[index] 87 | 88 | 89 | class Post: 90 | """Message.""" 91 | 92 | def __init__(self, user, time_posted, content): 93 | """Initialise l'utilisateur, la date et le contenu.""" 94 | self.user = user 95 | self.time_posted = time_posted 96 | self.content = content 97 | 98 | def display(self): 99 | """Affiche le message.""" 100 | print(f"Message posté par {self.user} le {self.time_posted}:") 101 | print(self.content) 102 | 103 | 104 | class FilePost(Post): 105 | """Message comportant un fichier.""" 106 | 107 | def __init__(self, user, time_posted, content, file): 108 | """Initialise le fichier.""" 109 | super().__init__(user, time_posted, content) 110 | self.file = file 111 | 112 | def display(self): 113 | """Affiche le contenu et le fichier.""" 114 | super().display() 115 | print("pièce jointe:") 116 | self.file.display() 117 | 118 | 119 | class Thread: 120 | """Fil de discussions.""" 121 | 122 | def __init__(self, title, time_posted, post): 123 | """Initialise le titre, la date et les posts. 124 | 125 | Attention ici: on commence par un seul post, celui du sujet. 126 | Les réponses à ce post ne pourrons s'ajouter qu'ultérieurement. 127 | En effet, on ne créé pas directement un nouveau fil avec des réponses. ;) 128 | """ 129 | self.title = title 130 | self.time_posted = time_posted 131 | self.posts = [post] 132 | 133 | def display(self): 134 | """Affiche le fil de discussion.""" 135 | print("----- THREAD -----") 136 | print(f"titre: {self.title}, date: {self.time_posted}") 137 | print() 138 | for post in self.posts: 139 | post.display() 140 | print() 141 | print("------------------") 142 | 143 | def add_post(self, post): 144 | """Ajoute un post.""" 145 | self.posts.append(post) 146 | -------------------------------------------------------------------------------- /exercices/p2c5_forum.py: -------------------------------------------------------------------------------- 1 | """Définit les classes propres à notre forum. ;)""" 2 | 3 | import time 4 | from abc import ABC 5 | 6 | 7 | class File(ABC): 8 | """Fichier.""" 9 | 10 | def __init__(self, name, size): 11 | """Initialise le nom et la taille.""" 12 | self.name = name 13 | self.size = size 14 | 15 | def display(self): 16 | """Affiche le fichier.""" 17 | pass 18 | 19 | 20 | class ImageFile(File): 21 | """Fichier image.""" 22 | 23 | def display(self): 24 | """Affiche l'image.""" 25 | print(f"Fichier image '{self.name}'.") 26 | 27 | 28 | class GifImageFile(ImageFile): 29 | """Fichier image Gif.""" 30 | 31 | def display(self): 32 | """Affiche l'image.""" 33 | super().display() 34 | print("L'image est de type 'Gif'.") 35 | 36 | 37 | class PNGImageFile(ImageFile): 38 | """Fichier image PNG.""" 39 | 40 | def display(self): 41 | """Affiche l'image.""" 42 | super().display() 43 | print("L'image est de type 'PNG'.") 44 | 45 | 46 | class User: 47 | """Utilisateur.""" 48 | 49 | def __init__(self, username, password): 50 | """Initialise le nom d'utilisateur et le mot de passe.""" 51 | self.username = username 52 | self.password = password 53 | 54 | def login(self): 55 | """Connecte l'utilisateur.""" 56 | print(f"L'utilisateur {self.username} est connecté.") 57 | 58 | def post(self, thread, content, file=None): 59 | """Poste un message dans un fil de discussion.""" 60 | if file: 61 | post = FilePost(self, "aujourd'hui", content, file) 62 | else: 63 | post = Post(user=self, time_posted="aujourd'hui", content=content) 64 | thread.add_post(post) 65 | return post 66 | 67 | def make_thread(self, title, content): 68 | """Créé un nouveau fil de discussion.""" 69 | post = Post(self, "aujourd'hui", content) 70 | return Thread(title, "aujourd'hui", post) 71 | 72 | def __str__(self): 73 | """représentation de l'utilisateur.""" 74 | return self.username 75 | 76 | 77 | class Moderator(User): 78 | """Utilisateur modérateur.""" 79 | 80 | def edit(self, post, content): 81 | """Modifie un message.""" 82 | post.content = content 83 | 84 | def delete(self, thread, post): 85 | """Supprime un message.""" 86 | index = thread.posts.index(post) 87 | del thread.posts[index] 88 | 89 | 90 | class Post: 91 | """Message.""" 92 | 93 | def __init__(self, user, time_posted, content): 94 | """Initialise l'utilisateur, la date et le contenu.""" 95 | self.user = user 96 | self.time_posted = time_posted 97 | self.content = content 98 | 99 | def display(self): 100 | """Affiche le message.""" 101 | print(f"-- Message posté par {self.user} {self.time_posted} --") 102 | print(self.content) 103 | 104 | 105 | class FilePost(Post): 106 | """Message comportant un fichier.""" 107 | 108 | def __init__(self, user, time_posted, content, file): 109 | """Initialise le fichier.""" 110 | super().__init__(user, time_posted, content) 111 | self.file = file 112 | 113 | def display(self): 114 | """Affiche le contenu et le fichier.""" 115 | super().display() 116 | print("pièce jointe:") 117 | self.file.display() 118 | 119 | 120 | class Thread: 121 | """Fil de discussions.""" 122 | 123 | def __init__(self, title, time_posted, post): 124 | """Initialise le titre, la date et les posts. 125 | 126 | Attention ici: on commence par un seul post, celui du sujet. 127 | Les réponses à ce post ne pourrons s'ajouter qu'ultérieurement. 128 | En effet, on ne créé pas directement un nouveau fil avec des réponses. ;) 129 | """ 130 | self.title = title 131 | self.time_posted = time_posted 132 | self.posts = [post] 133 | 134 | def display(self): 135 | """Affiche le fil de discussion.""" 136 | print("----- THREAD -----") 137 | print(f"titre: {self.title}, date: {self.time_posted}") 138 | print() 139 | for post in self.posts: 140 | post.display() 141 | print() 142 | print("------------------") 143 | 144 | def add_post(self, post): 145 | """Ajoute un post.""" 146 | self.posts.append(post) 147 | 148 | 149 | def main(): 150 | """Lance le code principal.""" 151 | user = User("John", "superpassword") 152 | moderator = Moderator("Lucie", "helloworld") 153 | 154 | cake_thread = user.make_thread("Gâteau à la vanille 🍰 ???", "Vous aimez ou non ?") 155 | cake_thread.display() 156 | 157 | moderator.post(cake_thread, content="Oui j'aime beaucoup ! 😚") 158 | cake_thread.display() 159 | 160 | irrelevant_post = user.post(cake_thread, content="Et vous aimez les voitures ?") 161 | response = moderator.post(cake_thread, content="C'est hors sujet sur ce forum 😕") 162 | cake_thread.display() 163 | 164 | print() 165 | print("après quelques minutes, le modérateur supprime les messages hors sujets...") 166 | print() 167 | # importer time n'était pas necessaire, c'est un plus: 168 | time.sleep(2) 169 | moderator.delete(cake_thread, irrelevant_post) 170 | moderator.delete(cake_thread, response) 171 | cake_thread.display() 172 | 173 | image = PNGImageFile(name="image de gâteau", size=3) 174 | user.post(cake_thread, content="Voici une image de mon gâteau !", file=image) 175 | moderator.post(cake_thread, "Woah, sublime !") 176 | cake_thread.display() 177 | 178 | 179 | main() 180 | --------------------------------------------------------------------------------