{Python}
Orienté Objet
# CHAPTER 1
La Programmation Orienté Objet
{Python}
- Notions de base
- Encapsulation
- Héritage
- Polymorphisme
- Abstraction
Restant à voir
- Aucun ¯\_(ツ)_/¯
Principes abordés
<
Les classes 😎
# PRESENTING CODE
class Robot():
# une parfaite coquille vide,
# absolument inutile ...
passUne classe est un plan, un patron, une description de l'objet à représenter
Les objets ☕🍺🪑
# PRESENTING CODE
class Robot():
# une parfaite coquille vide,
# absolument inutile ...
pass
# Oh la belle instance de classe !
# Naissance de votre premier objet
r = robot()
# Robot, fait des trucs !
r.do_something()Un objet est l'instance d'une classe
Un objet est l'instance d'une classe
Un objet est manipulable
Une classe est une description
Vous connaissez déjà quelques objets
String
List
Tuple
Dictionnaire
s = "hello"
t = ('a','b','c','d','b','b')
l = ['a','b','c','d']
d = {'a':1, 'b':2, 'c':3, 'd':4}
# show some 'str' methods
str
isinstance(s, str)
s.upper()
s.capitalize()
s.join('_1_','_2_','_3_')
# show some 'tuple' methods
tuple
isinstance(t, tuple)
t.count('b')
t.index('c')
# show some 'list' methods
list
isinstance(l, list)
l.append('b')
l.sort()
l.pop()
# show some 'list' methods
dict
isinstance(d, dict)
d.keys()
d.values()
d.pop('b')Attributs de classe
# PRESENTING CODE
class Robot():
name = "<unnamed>"
power = False
current_speed = 0
battery_level = 0
speaches = {'boot':'Hello world', 'shutdown':'Goodbye world'}
states = ['shutown', 'running']Les attributs décrivent les informations internes ce que nous devons représenter
Les méthodes de classe
# PRESENTING CODE
class Robot():
# les attibuts sont ici
def boot(self):
# Do someting to boot
pass
def shutdown(self):
# Do someting to shutdown
pass
def charge(self):
# Do someting to charge battery
passLes méthodes sont les moyens d’interagir avec l'objet que nous devons représenter
What the self ?!
# PRESENTING CODE
self représente l'instance de la classe
self est passé explicitement à chaque méthode
Spécifique à Python
Dans la plupart des VRAI langages POO
le mot this est utilisé au lieu de self
this est une propriété interne à la classe qui désigne l'appel du futur objet
Constructeur 🔨 et Destructeur 💣
# PRESENTING CODE
ROBOT_COUNT = 0
class Robot():
name = "<unnamed>"
def __init__(self, name=None):
if name:
self.name = name
global ROBOT_COUNT
ROBOT_COUNT += 1
def __del__(self):
print("%s Auto destruction NOW"%(self.name))
global ROBOT_COUNT
ROBOT_COUNT -= 1constructor_destructor.py
Les constructeurs / destructeurs sont
- des méthodes de classe
- automatiquement définits si non précisés
class Robot():
name = "<unnamed>"
power = False
states = ['shutown','running']
def __init__(self, name=None):
if name:
self.name = name
self.current_state = self.states[0]
self.power = False
# Python permet d'appeler directement la propriétés d'une classe
print(Robot.name)
print("Robot power is %s"%(Robot.power))
print(Robot.current_state)
# Oh la belle instance de classe : naissance d'un objet
r = Robot(name='Terminator')
print(r.name)
print("Robot power is %s"%(r.power))
print(r.current_state)
# Ceci n'a pas bougé
print(Robot.name)
print("Robot power is %s"%(Robot.power))
print(Robot.current_state)Votre premier objet
On voit ici que current_state n'est appelable qu'après instanciation
constructor_destructor_and_object_attribut.py
# CHAPTER 1
La Programmation Orienté Objet
Les spécificités Objet Python
{Python}
Les fonctions pour faire joujou
avec les objets
class Robot():
"""I am a robot """
name = 'Wall.E'
def action(self):
""" Turn the robot in action mode """
pass
r = Robot()
# Pour comparer votre objet
isinstance(r, Robot)
# Récupérer la valeur d'un attribut
getattr(Robot, 'name')
# Pour comparer votre objet
callable(Robot().action)
callable(Robot().action())
dir(Robot)
help(Robot)
# Avec plus d'infos
from pprint import pprint
import inspect
pprint(inspect.getmembers(Robot))
for element in dir(Robot):
if callable(getattr(Robot, element)):
print(element, 'is method')
else:
print(element, 'is attribut')
built_in_class_utilities.py
Les méthodes spécifiques Python
__built-in__ ou __dunder__
Représenter votre objet
class Robot():
def __init__(self, name, size):
self.name = name
self.size = size
def __str__(self): # must return a string
return "Robot %s [size: %s]"%(self.name, self.size)
def __repr__(self): # must return a string
return str({"name":self.name, "size":self.size})
r = Robot('Terminator', 'medium')
# __str__ call
print(str(r))
print(r) # print auto convert into string
# __repr__ call
print(repr(r))
r # in python command interpreter repr() is automatically called
built_in_class_object_display.py
Créer un itérateur de votre objet
class Robot():
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.data):
raise StopIteration
data = self.data[self.index]
self.index += 1
return data
r = Robot(['spam','foo','bar'])
for robot_data in r:
print(robot_data)built_in_class_methods.py
Les comparateurs
SIZES = {'small':1, 'medium':2, 'big':3}
class Robot():
def __init__(self, size='medium'):
self.size = SIZES[size]
def __eq__(self, robot): # equal
return (self.size == robot.size)
def __ne__(self, robot): # not equal
return (self.size != robot.size)
def __gt__(self, robot): # greater than
return (self.size > robot.size)
def __ge__(self, robot): # greater or equal
return (self.size >= robot.size)
def __lt__(self, robot): # less than
return (self.size < robot.size)
def __le__(self, robot): # less or equal
return (self.size <= robot.size)
built_in_class_methods.py
Il en existe en fait un paquet !
__setitem__
__getitem__
__delitem__
__len__
__contains__
__add__ / __iadd__
__sub__ / __isub__
__mul__ / __imul__
__truediv__ / __itruediv__
__call__
....
et bien d'autres :)
Pas d'exo, mais retenez bien l'existence de ces méthodes utilisées par Python qu'on appelle
__built-in__ ou __dunder__
- Encapsulation
- Héritage
- Polymorphisme
- Abstraction
Restant à voir
- Notions de base
Principes abordés
La Programmation Orienté Objet
{Python}
<
L'encapsulation
Accesseurs et Mutateurs
-
Les accesseurs sont des méthodes qui permettent de retourner la valeur d’un attribut.
-
Les mutateurs permettent de modifier la valeur d’un attribut.
Votre premier concept Objet
class Robot():
current_speed = 0
# mutateur
def stop(self):
self.current_speed = 0
# mutateur
def move(self, speed):
if type(speed) == int:
self.current_speed = speed
# accesseur
def speed(self):
return self.current_speedPermet de masquer un certain nombre d’attributs et de méthodes afin de garder une cohérence dans la gestion de l’objet. Cela dissocie ce qui est interne à l’objet de ce qui est destiné à être utilisé par d’autres objets ou l’utilisateur

Attributs privés / publics
class Robot():
# private attributes
__name = '<unnamed>'
__current_speed = 0
# public attribute
mission = '<unknown>'
# protected attribute
_secret = '42'
# Simple style getter / setter
def stop(self):
self.__current_speed = 0
def move(self, speed):
if type(speed) == int:
self.__current_speed = speed
def speed(self):
return self.__current_speed
# Python style getter / setter
@property
def name(self):
return self.__name
@name.setter
def name(self,new_name):
self.__name = new_name
encapsulation_private_public.py
protected
public
private
r = Robot()
r.name = "Termonator"
r.mission = "Kill them all"
r.move(100)
print(r.name + "\nSpeed:", r.speed())
print("Mission", r.mission)
print("Secret", r._secret)
IMPORTANT : En Python les notions de protected n'existent pas. Ce nommage est une convention pour inciter le développeur à ne pas utiliser cet attribut
double underscore
simple underscore
aucun underscore
Attributs privés / publics

Attention aux pièges de syntaxe
public
private
__foobar__
__foobar
foobar__
public
foobar
public
Attention aux pièges de syntaxe
piège courant
protected
public
_foobar
par convention
!!🚧
Protéger sa classe avec les __slots__
class Robot:
# Empty class :
# nothing declared here
pass
r = Robot()
r.name = 'Roger'
print(r.name)
r.hacked = '000101111001'
print(r.hacked)class Robot:
__slots__ = ('name', 'power')
def __init__(self, name='', power=False):
self.name = name
self.power = power
r = Robot(name='Roger', power=False)
r.name = 'Super Roger'
print(r.name)
# Will throw an error
r.hacked = '000101111001'
print(r.hacked)encapsulation_private_public_with_slots.py
Exoooooo 1
- Lorsque je crée mon robot, je veux pouvoir lui attribuer un nom
- Mon robot doit pouvoir s'allumer
- Mon robot doit pouvoir s'éteindre
- Mon robot doit pouvoir charger sa batterie à 100%, allumé ou non
- Le temps de charge ne peut pas être immédiat (10s max)
- Mon robot doit afficher sont % de batterie durant sa charge
- Mon robot doit pouvoir enregistrer une vitesse de déplacement
- Mon robot doit pouvoir me donner sa vitesse de déplacement
- Mon robot doit pouvoir arrêter son déplacement sur commande
- Mon robot doit pouvoir me fournir un résumé de son état global
- Une fois terminé, commitez votre code sur Github
- Je jouerai alors avec votre objet pour interagir avec lui

class Robot():
__name = "<unnamed>"
__power = False
__current_speed = 0
__battery_level = 0
__states = ['shutown', 'running']
"""
Give your best code here ( •̀ ω •́ )✧
"""Classe de départ
exo1_starter_template.py
La Programmation Orienté Objet
{Python}
Les décorateurs Objet Python
@classmethod
class Robot():
__name = 'Simple Robot'
def __init__(self, name):
self.__name = name
# getter
@property
def name(self):
return self.__name
@classmethod
def get_original_name(cls):
return cls.__name
r = Robot('Roger le robot')
print(r.name)
print(r.get_original_name())class_methods_decorators.py
@staticmethod
class Robot():
__name = 'Simple Robot'
def __init__(self, name):
self.__name = name
# getter
@property
def name(self):
return self.__name
@staticmethod
def calculate(arg1, arg2):
print('La réponse est %s'%(arg1+arg2))
Robot.calculate(20+22)
class_methods_decorators.py
@annotations custom
def SecurisedAction(f):
def decorator(*args): # on emploi parfois le nom 'wrapper'
obj = args[0]
if obj.safety_enabled:
print('Robot is not allowed to do any action... ', str(f))
else:
return f(*args)
return decorator
class Robot():
__safety = False
@property
def safety_enabled(self):
return self.__safety
def enable_safety(self):
self.__safety = True
@SecurisedAction
def fire(self):
print('pew pew !')
@SecurisedAction
def run(self):
print("let's goooo")
r = Robot()
r.run()
r.enable_safety()
r.fire()decorators_bind_class_to_method.py
# CHAPTER 1
La Programmation Orienté Objet
Comparatif syntaxique
Python VS Java VS C++
{Python}
class Lamp {
private boolean power;
public void turnOn() {
this.power = true;
}
public void turnOff() {
this.power = false;
}
private void switch() {
this.power = ! this.power;
}
public boolean isOn() {
return this.power;
}
}
class Main {
public static void main(String[] args) {
Lamp led = new Lamp();
led.turnOn();
if(led.isOn()){
// do stuff
}
}
}class Lamp:
__power = False
def turn_on(self):
self.__power = True
def turn_off(self):
self.__power = False
def __switch(self):
self.__power = not self.__power
def is_on(self):
return self.__power
if __name__ == '__main__':
led = Lamp()
led.turn_on()
if led.is_on():
pass # do stuffPython
Java
Python a une approche Uniform Access Principle. Les notions privé/publique sont donc moins intégrées au langage
class Lamp {
private:
bool power = false;
private voir switch() {
this.power = ! this.power;
}
public:
void turnOn() {
this.power = true;
}
void turnOff() {
this.power = false;
}
bool isOn() {
return this.power;
}
};
int main() {
Lamp led;
led.turnOn();
if(led.isOn()){
// do stuff
}
}Python
C++
class Lamp:
__power = False
def turn_on(self):
self.__power = True
def turn_off(self):
self.__power = False
def __switch(self):
self.__power = not self.__power
def is_on(self):
return self.__power
led = Lamp();
led.turn_on();
if led.is_on() :
pass # do stuffDu fait que Python soit un langage scripté et interprété, il est le seul langage objet populaire à devoir passer sa propre instance via self (=this)
- Héritage
- Polymorphisme
- Abstraction
Restant à voir
- Notions de base
- Encapsulation
Principes abordés
La Programmation Orienté Objet
{Python}
<
L’héritage permet, à partir d’une classe existante (parent), de définir une nouvelle classe (enfant) auquel on ajoute de nouveaux attributs et de nouvelles méthodes.
La classe enfant bénéficie dès sa définition de l'ensemble des attributs et méthodes public ou protected de la classe parent, mais pas les attributs et méthodes private.
L’héritage
Remote
Robot
operated
Automate
Unmanned
Autonomous
Unmanned
Unmanned
Unmanned
Q-UGV
Unmanned
UGV
Unmanned
UUV
Unmanned
UGV
Unmanned
UAV
L’héritage permet aussi de redéfinir les méthodes héritées de l’objet parent plutôt que d’en créer de nouvelles. Cette pratique s’appelle la redéfinition.
class GroundRobot(FieldTypeRobot):
def __init__(self, name):
super().__init__(name, 'ground')
class AirRobot(FieldTypeRobot):
def __init__(self, name):
super().__init__(name, 'air')
class UnderseaRobot(FieldTypeRobot):
def __init__(self, name):
super().__init__(name, 'undersea')
class SurfaceRobot(FieldTypeRobot):
def __init__(self, name):
super().__init__(name, 'surface')
ugv = GroundRobot('Wall.E')
uav = AirRobot('Megacopter')
usv = UnderseaRobot('Nautilus')
uuv = SurfaceRobot('Titaniktou')
ugv.status()
uav.status()
usv.status()
uuv.status()from encapsulation_good_pratices import Robot
class FieldtypeRobot(Robot):
__field = None
def __init__(self, name, field):
self.__field = field
super().__init__(name)
# redéfinition
def __del__(self):
pass # do not print message enymore !
@property
def field(self):
return self.__field
# redéfinition
def status(self):
print("%s (%s) status: %s [%s%% battery]"%(self.name, self.field, self.current_status, self.battery_level))heritage.py
heritage.py

Toute classe de base Python hérite automatiquement de la classe object
# Les deux classes suivants sont équivalentes
class Robot():
# héritage de 'object' implicite
pass
class Robot(object):
# héritage de 'object' explicite
pass
dir(object)
L'héritage multiple et les __slots__ ne sont pas entièrement compatible
Héritage multiple
class Robot(Robot):
def charge(self):
pass
class WalkingRobot(Robot):
def walk(self):
pass
class RidingRobot(Robot):
def ride(self):
pass
class Megatron(WalkingRobot, RidingRobot):
def transform(self):
pass
mega = Megatron()
mega.walk() # from WalingRobot
mega.transform() # from Megatron
mega.ride() # from RidingRobot
mega.charge() # from Robotdepuis Python3.10
Multiple inheritance with multiple slotted parent classes can be used, but only one parent is allowed to have attributes created by slots (the other bases must have empty slot layouts) - violations raise TypeError.
Explications plus détaillées ici
Héritage multiple

Exoooooo 2
Une fois terminé, commitez votre code sur Github
- Un Cyborg est un mélange d'humain et de robot
- Un humain doit posséder un sexe (H / F)
- Un humain doit pouvoir manger un ou plusieurs aliments
- Un humain doit pouvoir digérer ce qu'il a mangé pas très important, faire en dernier si vous avez le temps
- Réutiliser la class Robot faite dans l'exo 1. Sans copier/coller dans le fichier please ;)
- Bonus : ajouter une méthode fun au Cyborg
on passe direct' à la pratique
créer un Cyborg
class Robot():
# Robot class content here
pass
class Human():
# Human class content here
pass
class Cyborg(Robot, Human):
def __init__(self, name, sexe):
# initiate Robot parent class
Robot.__init__(self, name)
# initiate Human parent class
Human.__init__(self, sexe)
cyborg = Cyborg('Deux Ex Machina', 'M')
print(cyborg.name, 'sexe', cyborg.sexe)
print('Charging battery...')
cyborg.charge()
cyborg.status()
cyborg.eat('banana')
cyborg.eat(['coca', 'chips'])
cyborg.digest()Classe de départ
heritage_multi.py
L'héritage multiple
se définit ici
Exemple simple
class Robot():
# Robot class content here
battery = 0
def __init__(self, battery):
self.battery = battery
def charge(self):
pass
class Human():
# Human class content here
name = ''
def __init__(self, name):
self.name = name
def breath(self):
pass
class Cyborg(Robot, Human):
def __init__(self, name, battery):
# initiate Human parent class
Human.__init__(self, name)
# initiate Robot parent class
Robot.__init__(self, battery)
def night_vision(self):
pass
cyborg = Cyborg('Deux Ex Machina', 100)
# utilisation des attributs publics de Human et Robot
print('Name', cyborg.name)
print('Battery level', cyborg.battery+'%')
# appel de méthode Human
cyborg.breath()
# appel de méthode Robot
cyborg.charge()
# appel de méthode Cyborg
cyborg.night_vision()Héritage multiple

Exoooooo 2
Une fois terminé, commitez votre code sur Github
- Un Cyborg est un mélange d'humain et de robot
- Un humain doit posséder un sexe (H / F)
- Un humain doit pouvoir manger un ou plusieurs aliments
- Un humain doit pouvoir digérer ce qu'il a mangé pas très important, faire en dernier si vous avez le temps
- Réutiliser la class Robot faite dans l'exo 1. Sans copier/coller dans le fichier please ;)
- Bonus : ajouter une méthode fun au Cyborg
on passe direct' à la pratique
créer un Cyborg
Héritage en diamant

Human
Cyborg
Robot
FlyingRobot
FlyingCyborg

from pprint import pprint
class Human():
pass
class Robot():
pass
class FlyingRobot(Robot):
pass
class Cyborg(Robot, Human):
pass
class FlyingCyborg(FlyingRobot, Cyborg):
pass
pprint(FlyingCyborg.mro())
""" Print output :
[<class '__main__.FlyingCyborg'>,
<class '__main__.FlyingRobot'>,
<class '__main__.Cyborg'>,
<class '__main__.Robot'>,
<class '__main__.Human'>,
<class 'object'>]
"""
mro : method resolution order
heritage_resolution_order.py
La résolution d'un appel se fait suivant la règle du premier chemin directe vers la première classe parente par rapport à la résolution gauche-droite des héritages
La recherche dans une classe ne se fait qu’une fois. Une classe de la hiérarchie dans l’héritage des classes Python est donc parcourue qu’une seule fois
- Polymorphisme
- Abstraction
Restant à voir
- Notions de base
- Encapsulation
- Héritage
Principes abordés
La Programmation Orienté Objet
{Python}
<
Le polymorphisme est un mécanisme important dans la programmation objet.
Il est la capacité d’un objet à posséder plusieurs formes. Ce principe découle de l’héritage.
Il permet de modifier le comportement d’une classe enfant par rapport à sa/ses classe(s) parent(s), en adaptant le comportement des objets suivant la redéfinition des méthodes.
Le polymorphisme
Le polymorphisme
class Robot():
# Robot class content here
pass
class Human():
# Human class content here
pass
class Cyborg(Robot, Human):
# Cyborg class content here
pass
cyb = Cyborg()
if issubclass(Cyborg, Human):
print("Cyborg est une sous classe de Human !")
if issubclass(Cyborg, Robot):
print("Cyborg est une sous classe de Robot !")
if isinstance(cyb, Human):
print("Wesh frère t'es un mec un vrai !")
if isinstance(cyb, Robot):
print("010110100101 101010100001 01010101110 !")La reconnaissance du parent
polymorphism_relations.py
def use_robots_for_mission(robot: FieldTypeRobot) -> bool:
"""
On attend ici un type FieldTypeRobot, ou tout autre classe hérité de FieldTypeRobot
"""
robot.start_mission()
try:
robot.ride()
except Exception as e:
print(e, " << mauvais appel, on est allé trop loin dans l'attente de l'objet")
finally:
print()
robots = [
GroundRobot('Wall.E'),
AirRobot('Megacopter'),
UnderseaRobot('Nautilus'),
SurfaceRobot('Titaniktou'),
]
for rob in robots:
use_robots_for_mission(rob)polymorphism_simple.py
Analysons ensemble un exemple un poil trapu...
Le polymorphisme
Ce principe est encore plus concret pour les langages typés
Python utilise le
duck typing
Le polymorphisme
class Robot{
public void mission(){
System.out.println("My mission is simple");
}
}
class FlyingRobot extends Robot {
public void mission(){
System.out.println("My mission is aerial");
}
}
class UnderwaterRobot extends Robot {
public void mission(){
System.out.println("My mission is underwater");
}
}
class Main {
public static void main(String[] args) {
Robot rob = new Robot();
rob.mission(); // as a Robot
Robot frob = new FlyingRobot();
frob.mission(); // as a FlyingRobot
Robot urob = new UnderwaterRobot();
urob.mission(); // as a UnderwaterRobot
}
}
En Java
Pas d'exo, mais retenez bien le principe de polymorphisme via l'héritage
- Abstraction
Restant à voir
- Notions de base
- Encapsulation
- Héritage
- Polymorphisme
Principes abordés
La Programmation Orienté Objet
{Python}
<
Les classes abstraites
Les classes abstraites permettent de définir par avance l'implémentation des méthodes des classes enfant.
Ainsi, on a l'assurance ses classes enfant auront bien le comportement défini et attendu par la classe parent abstraite.
Ce contrat est une interface de programmation.
Le module abc
from abc import ABCMeta
class Robot(metaclass=ABCMeta):
# Abstract class concept
# can be used here
passfrom abc import ABC
class Robot(ABC):
# Abstract class concept
# can be used here
passrecommandé
Par héritage
Par méta classe
Abstract Base Classes
Le module abc Python permet d'accéder à la définition d'une classe abstraite
OU
/!\ obsolète /!\
Utiliser une classe abstraite
from abc import ABCMeta
from abc import abstractmethod
class TimeRobot(metaclass=ABCMeta):
@property
@abstractmethod
def timezone(self):
pass
@classmethod
@abstractmethod
def default_timezone(cls):
pass
@staticmethod
@abstractmethod
def whattime():
pass
@timezone.setter
@abstractmethod
def timezone(self):
pass
@abstractmethod
def mission(self):
passimport time
class Robot(TimeRobot):
__timezone = 'Europe/London'
@property
def timezone(self):
return self.__timezone
@classmethod
def default_timezone(cls):
return cls.__timezone
@staticmethod
def whattime():
print('We are', time.asctime())
@timezone.setter
def timezone(self, timezone):
self.__timezone = timezone
def mission(self):
print('Start Robot mission : travel in time...')
try: # Can not use TimeRobot as object !
rob = TimeRobot()
except Exception as e:
print(e)
rob = Robot()
rob.timezone = 'America/Montreal'
rob.mission()
Robot.whattime()
Tout est là
abstract.py
abstract.py
Il est impossible
d'instancier une classe abstraite
!!! ATTENTION !!!
@abstractmethod doit être annoté après les autres décorateurs
L'ordre est hyper important :
from abc import ABCMeta, abstractmethod
class Robot(metaclass=ABCMeta):
@abstractmethod
def start_mission(self):
pass
class SuperRobot(Robot):
pass
sr = SuperRobot()
sr.start_mission()
"""
Traceback (most recent call last):
File "test.py", line 14, in <module>
sr = SuperRobot()
TypeError: Can't instantiate abstract class
SuperRobot with abstract methods start_mission
"""from abc import ABCMeta, abstractmethod
class Robot():
@abstractmethod
def start_mission(self):
pass
class SuperRobot(Robot):
pass
sr = SuperRobot()
sr.start_mission()
# OK, no error ¯\_(ツ)_/¯Attention aux embrouille !
utilisation de @abstractmethod sans être une classe abstraite
abstract_test.py
abstract_test.py
Classes abstraites

Exoooooo 3
Une fois terminé, commitez votre code sur Github
- En tant que client, je veux pouvoir jouer avec trois types de Véhicules différents : UUV, UAV, UGV
- Seul les Véhicules finaux doivent être utilisables
- Un Véhicules Unmanned doit exécuter une mission
- Mettre en avant un principe de classe abstraite
- Mettre en avant un principe de polymorphisme
- Mettre en avant un principe d'héritage multiple
- Pas d'algorithmes complexes, juste des print ;)

Sortez un bon vieux crayon pour schématiser vos dépendances d'héritages
place aux créateurs
from abc import ABCMeta, abstractmethod
""" You can use classes below or create your own 👍️"""
class UnmannedVehicule(metaclass=ABCMeta):
"""
An autonomous vehicle have to do his mission automatically.
This mission can be configured by an operator.
"""
pass
class AerialVehicule(metaclass=ABCMeta):
""" A vehicle made for aerial areas."""
pass
class GroundVehicule(metaclass=ABCMeta):
""" A vehicle made for ground fields."""
pass
class UnderseaVehicule(metaclass=ABCMeta):
""" A vehicle made for underwater sea."""
pass
class UAV():
"""Unmanned Aerial Vehicule"""
pass
class UUV():
"""Unmanned Undersea Vehicule"""
pass
class UGV():
"""Unmanned Ground Vehicule"""
pass
Classes de départ
heritage_multi.py
Aucun lien d'héritage n'est définit par défaut
La Programmation Orienté Objet
{Python}
Composer des classes
Garder à l'esprit qu'un objet peut être composé de plusieurs autres
class Leg():
...
class Arm():
...
class Head():
...
class Cyborg():
def __init__(self):
self.head = Head()
self.left_leg = Leg()
self.right_leg = Leg()
self.left_arm = Arm()
self.right_arm = Arm()Il est important de savoir jouer entre composition et héritage
class Human():
def __init__(self):
self.head = Head()
self.left_leg = Leg()
self.right_leg = Leg()
self.left_arm = Arm()
self.right_arm = Arm()
def walk(self, meters=0):
for m in range(meters):
self.right_leg.move()
self.left_leg.move()
class Robot():
def charge(self):
print('Charging battery')
class Cyborg(Human, Robot):
def __init__(self):
Human.__init__(self)
Robot.__init__(self)
self.laser = Laser()
self.rocket = Rocket()
cyb = Cyborg()
cyb.charge()
cyb.walk(meters=20)
cyb.laser.fire()
cyb.rocket.fire()class Member(metaclass=ABCMeta):
@abstractmethod
def move(self): # moving action
pass
class Leg(Member):
def move(self):
print('Do leg moving logic')
class Arm(Member):
def move(self):
print('Do leg moving logic')
class Head(Member):
def move(self):
print('Do head moving logic')
class Weapon(metaclass=ABCMeta):
@abstractmethod
def fire(self):
pass
class Laser(Weapon):
def fire(self):
print('Zap zap zap !')
class Rocket(Weapon):
def fire(self):
print('BOOOOM !')heritage_multi.py
La Programmation Orienté Objet
{Python}
Design Patterns
Designs patterns
Le plus complet


Le plus geek
Les sources de documentation qui vous aideront
Designs patterns
Les trois catégories
Patrons structurels
Patrons de création
Patrons comportementaux



<NOM/>
Abstract Factory
Singleton
Template Method
Decorator
Facade
Observer
Mediator
Proxy
Les plus utiles
<CATEGORIE/>
comportemental
création
création
structurel
structurel
comportemental
structurel
comportemental
Designs patterns
permet de créer des familles d’objets apparentés sans préciser leur classe concrète. La Factory utilise typiquement le principe de polymorphisme
Les plus utiles
Abstract Factory
Le client n’a pas besoin de connaître la classe concrète qu'il recevra de la Factory.



création
Singleton
Les plus utiles

L'utilisateur travaille toujours avec le même objet.
Permet de garantir l’unicité d’une instance pour une classe. En général pour contrôler l’accès à une ressource partagée..
Par exemple une Base de Données ou un fichier.

création
Permet de mettre une logique de structure dans la classe mère, mais laisse les sous-classes redéfinir la logique sans changer sa structure.
Les plus utiles

Template Method
Un plan architectural donné peut être légèrement remanié pour mieux répondre aux besoins d’un client.
Vous l'avez vu avec :
- Classes abtraites
- Méthodes abstraites
comportemental
Permet d’affecter dynamiquement de nouveaux comportements à des fonctions ou méthodes en les plaçant dans des emballeurs (wrappers) qui implémentent ces comportements.
Les plus utiles
Decorator
Les effets se cumulent si vous portez plusieurs couches de décorateurs.
Vous l'avez vu avec :
- @property
- @abstractmethod

structurel
Facade
Les plus utiles
Par analogie, lors d'une commande auprès d'un magasin, un opérateur joue le rôle de la façade pour l'ensemble des services du magasin
Permet de procurer une interface offrant un accès simplifié à une librairie, un framework ou à n’importe quel ensemble complexe logiciel.

Vous l'avez vu avec :
Le contexte __main__
... en quelque sorte.

structurel
Observer
Les plus utiles
Par analogie, lorsque vous vous inscrivez à une newsletter, vous n’avez plus besoin de vous rendre sur le site pour vérifier les actus. Le diffuseur vous envoie directement actus dès leur publication
Permet de mettre en place un mécanisme de souscription pour envoyer des notifications à plusieurs objets, au sujet d’événements concernant les objets qu’ils observent.


Evite ceci :
comportemental
Mediator
Les plus utiles
Par analogie, les appareils qui vont décoller ou atterrir sur dans un aéroport ne communiquent pas directement entre eux. Ils s’adressent à un Médiateur aérien (l'aéroport) qui orchestrera les communications et actions.
Permet de diminuer les dépendances chaotiques entre les objets. Il restreint les communications directes entre les objets et les force à collaborer uniquement via un objet médiateur.


comportemental
Proxy
Les plus utiles
Permet d’utiliser un substitut pour un objet. Elle donne le contrôle sur l’objet original, vous permettant d’effectuer des manipulations avant ou après que la demande ne lui parvienne.


Le proxy se déguise en objet base de données. Il peut gérer des actions et des données sans que le client ou que l’objet de la base de données ne le remarque.
Vous l'avez vu chez vous avec :
Votre VPN



structurel
{:Bonus:}
Les grandes batailles
de concepts
Function prog. vs Object prog.
class RobotWheel():
def move_forward(self):
self.x_pos += 1
def move_backward(self):
self.x_pos -= 1
class Robot():
def __init__(self):
self.left_wheel = RobotWheel()
self.right_wheel = RobotWheel()
def move_forward(self):
self.left_wheel.move_forward()
self.right_wheel.move_forward()
def move_backward(self):
self.left_wheel.move_backward()
self.right_wheel.move_backward()
# Main program infinite loop
if __name__ == '__main__':
robot1 = Robot()
robot2 = Robot()
while my_great_students_do_not_sleep == True:
robot1.move_forward()
robot2.move_backward()ROBOT1_ID = 'ROBOT1'
ROBOT2_ID = 'ROBOT2'
ROBOT_WHEELS_POSITION = {}
def move_robot_wheel_foward(robot_id):
global ROBOT_WHEELS_POSITION
ROBOT_WHEELS_POSITION[robot_id]['left'] += 1
ROBOT_WHEELS_POSITION[robot_id]['right'] += 1
def move_robot_wheel_backard(robot_id):
global ROBOT_WHEELS_POSITION
ROBOT_WHEELS_POSITION[robot_id]['left'] -= 1
ROBOT_WHEELS_POSITION[robot_id]['right'] -= 1
# Main program infinite loop
if __name__ == '__main__':
ROBOT_WHEELS_POSITION[ROBOT1_ID] = {'left':0, 'right':0}
ROBOT_WHEELS_POSITION[ROBOT2_ID] = {'left':0, 'right':0}
while my_great_students_do_not_sleep == True:
move_robot_wheel_foward(ROBOT1_ID)
move_robot_wheel_foward(ROBOT2_ID)
Centralisé vs décentralisé vs distribué

Réseau banquaire
Crypto monaie
internet
Monolitic vs Microservices
Tout en un. une unique application


Découplage des
responsabilités entre applications

Références utilisées
Programmation Objet Python (la base et l'encapsulation)
Programmation Objet Python (héritage/polymorphisme)
Programmation Objet guides complets (plus ou moins)
- https://datascientest.com/programmation-orientee-objet-guide-ultime
- https://realpython.com/python3-object-oriented-programming/
Pour pratiquer et s'amuser
https://www.codewars.com/
https://py.checkio.org/
02 - Python Orienté Objet
By Rémy Guillo du Bodan
02 - Python Orienté Objet
- 827