# CP Python: Séance 11
### Récapitulatif Séance 10
* [Jamboard](https://jamboard.google.com/d/1aP26MJL3nEnuKxnpn1CZ9NroOzLzno2YLgEjvXnCvyQ/viewer)
* [Guide de séance 10](https://hackmd.io/9IIs5vM4SR-SBlpHolO3CQ)
### Remarques
* Lundi 28, 11h => Polymorphisme
* Vendredi 8, 16h: Listes Chainées
* Samedi 9, 14h: Examen Blanc
## A préparer pour jeudi 24/12, 14h
### 1. Résoudre la fin de la QBF de la Séance 10 dans le [REPL](https://repl.it/@GuillaumeGst/Students-CP9-and-CP10-Python#employee.py)
__A.__
Dans un fichier `employee.py` écrivez une classe complète `Employee` dont les instances représentent un employé d’entreprise.
Un employé est caractérisé par son nom (un string) et son salaire (un entier positif). Il doit être possible de créer un nouvel employé avec un nom et un salaire et d’effectuer les opérations suivantes sur un objet `Employe`:
— Obtenir le nom de l’employé
— Obtenir le salaire de l’employé
— Obtenir un texte descriptif représentant l’employé sous la formen `nom : salaire`
— Augmenter le salaire de l’employé d’un certain pourcentage.
Après avoir défini cette classe `Employe` correctement, le code suivant devrait imprimer `Charles : 2750.0`.
```python
charles = Employe("Charles", 2500)
charles.augmente(10)
print(charles)
```
__B.__
Maintenant, supposez qu’on ajoute la méthode d’instance suivante à la définition de la classe `Employe`. Le but de cette méthode est d’ajouter le nom de famille au nom de l’employé.
```python
def add_lastname(lastname):
name += " " + lastname
```
Avec cette définition, le code suivant
```python
charles.add_lastname("Pecheur")
print(charles)
```
produirait une erreur plutôt que d’imprimer `"Charles Pecheur: 2750.0"`. Expliquez quelle erreur serait produit et corrigez la méthode ci-dessus afin d'avoir le résultat escompté. __NB__: Il y a 2 erreurs!
Maintenant considérez l’instruction suivante. On s’attend à ce que le string `"Kim Mens : 2640.0"` soit imprimé à l’écran. Est-ce que ce serait le cas pour votre code ? Est-ce que votre code supporte des appels chaînés comme dansl’instruction suivante ? Sinon, corrigez vos méthodes précédentes afin que cette instruction ait le comportement voulu.
```python
print(Employe("Kim", 2400).augmente(10).add_lastname("Mens"))
# doit imprimer "Kim Mens : 2640.0"
```
__C__
Écrivez ensuite quelques instructions Python qui effectuent ces différentes opérations:
- créer deux objets `Employe` représentant les frères Pierre et Nicolas ayant le même salaire de $2410$ euros ;
- applique une augmentation de salaire de $3\%$ à Pierre ;
- affiche les descriptifs de Pierre et Nicolas à l'écran.
Représentez graphiquement les instances créées avant et après l'augmentation du salaire de Pierre. => Créez un nouveau *Jamboard* que vous me partagerez.
### 2. Préparer la nouvelle matière
__Objectifs__
* Variables d'instance "privées" (ou masquées) et méthodes accesseurs;
* Variables et méthodes de classe;
* Héritage, redéfinition de méthodes, utilisation de `self` et `super()`;
* Méthodes magiques
__Préparation, étude et apprentissage__
- [ ] [S9 Restructuration: Classes et objets, méthodes magiques, composition](https://drive.google.com/file/d/1bPt4xlskMkpK5vl-rf11YtHiTVvEq6J2/view?usp=sharing) (tout sauf copie profonde)
* <u> Référence vers l'instance</u> (objet) appelante:`self`
```python
class NokiaPhone :
def __init__(self,s) :
self.marque = "Nokia"
self.serie = s
def print_type(self) :
print(self.marque + " " + str(self.serie))
nokia_kim = NokiaPhone(5110)
nokia_kim.print_type()
```
* <u>Composition de classe </u>: Un objet peut contenir (une référence vers) un autre. ***NB*** Déclaré dans la méthode `__init__` de *Album*.
* Un *Album* est composé de *Chanson*
* <u> Méthodes magiques </u>
- `__init__` pour initialiser les objets d'une classe => modifie le constructeur
- `__str__` pour retourner une représentation textuelle d'un instance d'une classe => modifie `str()`, `print()`
- `__eq__` pour définir l'égalité entres objets d'une classe => modifie `==`
- [ ] [S9 Introduction: Masquage d’information, variables et méthodes de classe, héritage](https://drive.google.com/file/d/1Zhp0vQ-TnSTI0HRt8YvNX0tgisJ7xK_n/view?usp=sharing) (tout)
| Problème | Solution |
| -------- | -------- |
| |  |
| Maintenant qu'ils sont mieux protégés, comment accéder à ces attributs privés *en lecture seule* ? | => *Méthodes accesseurs* 
|
| Maintenant qu'ils sont mieux protégés, comment accéder à ces attributs privés *en écriture* ? | => *Méthodes mutateurs* 
* <u> Variable de classe </u>: variable accessible à toutes les instances de la classe
```python
class Compte :
# class variable
taux = 0.02
def __init__(self, titulaire):
self.__titulaire = titulaire
self.__solde = 0
compte_kim = Compte("Kim")
compte_oli = Compte("Olivier")
print(
compte_kim.taux \
== compte_oli.taux \
== Compte.taux \
== 0.02) # ?
```
* <u> Héritage </u>:
* Permet de créer une nouvelle classe (_classe-fille_) à partir d'une classe existante (_classe-mère_).
* La classe-fille _hérite_ par défaut de toutes les méthodes et attributs de la classe-mère.
* Elle peut, indépendamment, avoir <u>en plus</u> ses propres méthodes et attributs ou <b>étendre/améliorer</b> celles/ceux hérité(e)s en utilisant notamment la référence `super()`.
| | |
| -------- | -------- |
| | |
| `super()` permet de référer à une classe-mère (ou _super-classe_) sans devoir la nommer explicitement. | |
- [ ] [S10 Restructuration: Variables d’instances privées, variables de classes privées, méthodes de classe, la portée des variables](https://drive.google.com/file/d/1qp_cewXq2ukxqu1EcYQycasNyeR6PQTA/view?usp=sharing) (tout sauf les tests unitaires)
* <u>Variable de classe privée et méthode de classe</u>
| | |
| -------- | -------- |
| | |
- [ ] [S11 Restructuration: Portée des variables](https://drive.google.com/drive/folders/1ADF6uYE0ksbcb2YoYDU4D_Cn1SQfGX0u) (tout sauf les tests unitaires)
| | |
| -------- | -------- |
|Play with Python Tutor Visualize [here](http://www.pythontutor.com/visualize.html#code=class%20Foo%20%3A%0A%20%20%20%20foo%20%3D%201%0A%20%20%20%20def%20__init__%28self,foo%29%3A%0A%20%20%20%20%20%20%20%20self.foo%20%3D%20foo%0A%0A%20%20%20%20def%20m%28self,%20foo%20%3D%202%29%3A%0A%20%20%20%20%20%20%20%20foo%20%3D%203%0A%20%20%20%20%20%20%20%20return%20foo%0A%0Afoo%20%3D%204%0Abar%20%3D%20Foo%28foo%2B2%29%0Aprint%28bar.m%285%29%29&cumulative=false&curInstr=0&heapPrimitives=true&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) | <img width=400 src="https://i.imgur.com/bgN4aJs.png">|
> ___NB___ Si vous rencontrez des problèmes de compréhension à la lecture des slides, allez retrouver les sections correspondantes dans le syllabus.
- [ ] Visionner cette vidéo sur [l'héritage](https://www.youtube.com/watch?v=fW4818AS88I)
- [ ] Comprendre (ne pas hésiter à tester dans Thonny/REPL) le code de [cette Annexe](https://syllabus-interactif.info.ucl.ac.be/syllabus/info1-theory/PART_III/appendix_code_account_class)
- [ ] Créez un nouveau REPL que vous me partagerez. Repréparer les exercices de la phase de démarrage: je vous interrogerai aléatoirement au moment-même ;-) ! [Lien](https://syllabus-interactif.info.ucl.ac.be/syllabus/info1-exercises/PART_III/MISSION_9/preparation)
- [ ] Si vous avez le temps, jetez déjà un oeil à la QBF de cette mission, accessible [ICI](https://www.docdroid.net/Cq94juN/mission-10-qbf-pdf). On la corrigera ensemble.
### 3. Exercices S11 => [nouveau REPL](https://repl.it/join/rjjsjcrw-guillaumegst) (sauf pour Question 3)
#### [Question 3: Rectangle et Figure](https://syllabus-interactif.info.ucl.ac.be/syllabus/info1-exercises/PART_III/MISSION_9/preparation)
> * Quelles sont les variables d'instance qu'une instance de la classe Rectangle peut utiliser ?
> * Que se passe-t il lorsqu'une instance r de la classe Rectangle est créé?
> * Que fait l'appel à `super()` dans la méthode `__init__` de la classe Rectangle ?
> * Que se passe-t il si on met cet appel à super() comme dernière instruction dans la méthode `__init__` de la classe Rectangle ?
#### [Question 4: Variables privées et héritage](https://syllabus-interactif.info.ucl.ac.be/syllabus/info1-exercises/PART_III/MISSION_9/preparation)
> Pour éviter de rendre accessible les variables x, y et visible à l'extérieur d'une Figure, quelqu'un modifie le code de la classe Figure. Concrètement, pour rendre ces variables privés, on ajoute un __ à leur nom
> * Malheureusement, le code de la classe Rectangle, qui hérite de la classe Figure ne marche plus maintenant. Quel est le problème?
> * Corrigez le code de Figure et Rectangle afin que les instructions suivantes produisent le résultat voulu. Implémentez aussi correctement la méthode `surface()` de la classe Rectangle.
#### [Question 5 : Carre]
> * Comment feriez-vous maintenant pour définir une classe `Carre` qui étend la classe `Rectangle` et permet de représenter un carré ? Ecrivez la méthode d'initialisation de la classe `Carre` (un carré se construit en indiquant les coordonnées de son centre de gravité et la longueur de son côté)
> * Quelles sont les méthodes que vous devez redéfinir dans la classe `Carre` ?
> * Ecrivez une méthode `perimetre()` de la classe `Rectangle` qui retourne le périmètre du rectangle. Que faudrait-il faire pour avoir une méthode perimetre de la classe `Carre` ?
#### [Question 6: Similitude]
> * Définissez une méthode `__eq__` pour la classe Figure, telle que deux figures sont égales si leur surface est égale.
> * Que se passe-t il si on veut comparer deux rectangles ayant la même surface?
> * Que se passe-t il si on veut comparer un rectangle avec un carré ayant la même surface?
#### [QBF (30 min)](https://www.docdroid.net/Cq94juN/mission-10-qbf-pdf)
Dans le contexte de gestion d’une bibliothèque de média, chacun des objets de cette bibliothèque estune instance de la classe `Item` ci-dessous.
```python
class Item :
def __init__(self,author,title,serial):
"""
Méthode d'initialisation.
@pre author et title sont des valeurs de type String
serial est un entier > 0
@post Une instance de la classe est créée, et représente un objet ayant
comme auteur author, comme titre title et comme numéro de série serial
"""
self.__author = author
self.__title = title
self.__serial = serial
def __str__(self):
"""
Méthode de conversion en string.
@pre -
@post le string retourné contient une représentation de cet objet sous la
forme: [num série] Auteur, Titre
"""
### À compléter ###
```
1. Compléter la méthode `__str__`de la classe Item.
2. Écrire entièrement la classe CD en utilisant l'héritage.
- Un CD est lui même un item de la bibliothèque avec une information supplémentaire : la durée de l’album en secondes (un entier suffira). On doit pouvoir créer un nouvel objet CD par exemple avec l’instruction :
`cd = CD("Radiohead","The Bends",2917)`
- Les trois paramètres passés au constructeur CD() sont l’auteur, le titre et une durée en secondes.
- On doit pouvoir obtenir une représentation textuelle d’un CD grâce à la méthode `__str__`, qui renvoie par exemple :
`[100000] Radiohead, The Bends (2917 s)`
- Remarquez que chaque Item possède un numéro de série serial propre à l’objet (pour pouvoir différencier plusieurs exemplaires d’un même livre par exemple).
- Ce numéro de série est fourni en paramètre du constructeur pour un Item mais doit être généré automatiquement et commencer à 100000 pour un CD.