0% ont trouvé ce document utile (0 vote)
34 vues45 pages

05 Python

Transféré par

ousmane.diakhate08
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
34 vues45 pages

05 Python

Transféré par

ousmane.diakhate08
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Programmation Orientée Objet

C3P

Vincent Aranega
[email protected]

Université de Lille

1/45
Table of contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

2/45
Table of Contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

3/45
C’est quoi la programmation orientée objet ?

Des idées ?

4/45
C’est quoi la programmation orientée objet ?

I Création d’artefacts “autonomes”


I Encapsulation
I Un objet représente un concept, une idée ou une entitée
I On met ensemble:
I les données
I les comportements associés
I L’état de l’application passe par les différents états des objets
I Paradigme de programmation
,→ il s’agit d’une façon de penser la construction d’un logiciel
basée sur certains principes fondamentaux et définis

5/45
Quelles conséquences ?

En pratique
I On créer des classes d’objets
I Un objet possède une structure interne et un comportement
I Un objet sait comment intéragir avec ses paires

En résumé
La programmation orientée objet met en avant la définition et
l’intéraction de briques logicielles appelées objets.

6/45
Histoire de Python

I Langage développé à par Guido van Rossum à partir de 1989


aux Pays-bas
I Recherche sur les systèmes d’exploitation :
I développé initialement pour simplifier la production de
programmes pour l’OS Amoeba
I typage dynamique
I langage hybride

1989 Guido débute le développement de Python


1991 Python 0.9 est rendu publique
1994 Python 1.0 est distribué avec des éléments fonctionnels
2000 Python 2.0 est distribué
2008 Python 3.0 est distribué

7/45
Points clé de la programmation objet ?

I Système de classe (et/ou méta-classes)


I Héritage
I Polymorphisme
I Encapsulation

Et pour Python ?
I Héritage multiple
I Modèle objet à base d’attributs
I Attributs (presque) toujours publique (rarement d’accesseurs)
I Duck typing

8/45
Table of Contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

9/45
Rappels généraux
I Pas de séparateurs d’instructions, on revient à la ligne.
I Les commentaires commencent par #.
I L’instruction print permet d’afficher n’importe quel objet
(fonction polymorphe).
I https://docs.python.org/3/tutorial/
introduction.html
a = 1
b = a + 4
a, b = b, a
if b == 5:
print(’Value is’, b)
else:
print("I don’t care")

Attention
Gestion des blocs par indentation
10/45
Rappels – list/tuple/dict

I Les listes sont mutables et peuvent contenir n’importe quel


type d’éléments.
I Les tuples sont immutables.
I Les dictionnaires permettent d’associer n’importe quel valeur à
une autre.
a = [1]
a.append(2) # a == [1, 2], a[0] vaut 1 et a[1] vaut 2

b = (1, 2, 3) # a[0] vaut 1, a[1] vaut 2 ...etc

c = {’a’: 2, ’b’: 3}
c[’c’] = 4 # c[’a’] vaut 2 ...etc

11/45
Rappels – boucles for

I Les boucles for itère sur des iterable .


I Beaucoup de type sont itérables (ex: les dicts, les tuples,
string...etc)
c = {’a’: 2, ’b’: 3, ’c’: 4}
for x in c:
print(x) # Iteration sur les clefs seulement

for k, v in c.items():
print(k, v) # Iteration sur les clefs valeurs

12/45
Création de classes
I La création de classe se fait avec le mot clef : class
I La méthode permettant d’init. les instances est __init__
I On accède à un attribut ou une fonction par la notation pointé.

class MaClass(object):
pass

class Point(object):
def __init__(self, x, y=0):
self.x = x
self.y = y

c1 = Point(x=3)
c2 = Point(x=3, y=4)
c3 = Point(4, 5)

print(c1.y) # affiche 0
print(c3.x) # affiche 4

13/45
Accès aux attributs

I Pas d’accesseurs ! En Python, on est entre adultes consentant


I Si on veut un attribut privé, la conventions veut qu’on le
préfixe avec un _
I Si on veut vraiment masquer un attribut, il faut préfixer avec
__ (il est rare de devoir avoir recours à ça en Python)
c1 = Point(x=3)
c2 = Point(y=4, x=3)
c3 = Point(4, 5)

print(c1.y) # affiche 0
print(c3.x) # affiche 4

14/45
Attributs dérivés
I possibilité d’avoir des attributs en lecture seule
I possibilité d’impacter la façon dont on lit ou écrit une donnée
class Person(object):
def __init__(self, birth_year):
self.year = birth_year

@property
def age(self):
import datetime; now = datetime.datetime.now()
return now.year - self.year

@age.setter
def age(self, new_age):
import datetime; now = datetime.datetime.now()
self.year = now.year - new_age

p = Person(2000)
print(p.age) # Declanche la methode ’age’
p.age = 30 # Declanche la methode ’age’ comme setter
p.year # 1989 si l’annee courante est 2019
15/45
Variables de classes
I Les variables de classes sont partagées par toutes les instances
I On accède aux variables depuis une instance ou directement
depuis la classe
class Point(object):
default_x = 5
default_y = 5

def __init__(self):
self.x = self.default_x
self.y = self.default_y

def addition(self, other):


return Point(self.x + other.x, self.y + other.y)

p1 = Point()
p2 = Point()
p2.x = 10
p3 = p1.addition(p2)
assert p1.default_x == Point.default_x
16/45
Méthodes statiques et méthodes des classes
Attention
I y a une différence entre méthode statique et méthode de classes
class Spam(object):
@classmethod
def egg(cls, i):
print("I know", cls, i)

@staticmethod
def bacon(i):
print("I only know", i)

def usage(self):
self.egg(4)
self.bacon(3)

Spam().usage()
Spam.egg(4)
Spam.bacon(5)

17/45
Classes et héritage multiple

I Python supporte l’héritage multiple

Figure: Problème du diamant

I Résolution par l’algorithme de linéarisation C3

18/45
Classes et héritage multiple

class A(object):
def display(self):
self.disp()

class B(A):
def disp(self):
print(’In B’)

class C(A):
def disp(self):
print(’In C’)

class D(B, C):


pass

D.mro() # returns (D, B, C, A)


d = D()
d.display() # print what?

19/45
Surcharge de méthodes
I La surcharge de méthode se fait uniquement par rapport au
nom de la méthode.
class A(object):
def spam(self):
cls_name = self.__class__.__name__
print(f"I’m in spam from A, called from {cls_name}")

class B(A):
def spam(self):
print("I’m in spam from B")

class C(A):
def spam(self):
super().spam()
print("Now I’m spam from C")

B().spam()
C().spam()

20/45
Typage dynamique et Duck Typing
I “If it walks like a duck and it quacks like a duck, then it must
be a duck”
I On considère des protocols (équivalent d’interfaces) mais qui
ne sont pas explicitement définis
class Duck(object):
def fly(self):
print("Duck flying")

class Airplane(object):
def fly(self):
print("Airplane flying")

class Whale(object):
def swim(self):
print("Whale swimming")

for animal in Duck(), Airplane(), Whale():


animal.fly()

21/45
Table of Contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

22/45
Dunder methods (ou magic methods)
I Il est possible de surcharger/réutiliser les opérateurs et
structures de base de Python
I Cela permet de donner des APIs plus fluide et simple à
manipuler
I ATTENTION : Il ne faut pas en abuser si ce n’est pas
nécessaire
class Point(object):
def __init__(self, x=5, y=5):
self.x = x
self.y = y

def __add__(self, other):


return Point(self.x + other.x, self.y + other.y)

p1 = Point()
p2 = Point(y=6)
p3 = p1 + p2

23/45
Dunder methods – liste vraiment non exhaustive

__eq__(self, other) self == other


__pos__(self) +self
__neg__(self) -self
__invert__(self) ~self
__bool__(self) bool(self)

__getattr__(self, name) self.name


__setattr__(self, name, val) self.name = val
__getattribute__(self, name) self.name

__getitem__(self, key) self[key]


__setitem__(self, key, val) self[key] = val

__iter__(self) for x in self


__contains__(self, value) value in self
__call__(self [,...]) self(args)

24/45
Reflexion dans les langages

I Abilité d’un programme à s’examiner et à controler sa propre


implémentation
I La reflexion est composé de deux “techniques”:
1. l’instropection : capacité d’un programme à examiner son
propre état
2. l’intercession : capacité d’un programme à modifier son propre
état d’exécution ou d’altérer sa propre interprétation ou
signification
I Pourquoi est-ce utile ?
I Étendre un langage ou son design
I Construire des environnements de programmation
I Produire d’outils de développement avancés
I Produire des applications s’auto-modifiant ou
s’auto-optimisant

25/45
Accès reflexifs aux éléments d’un programme
I la fonction globals () retourne un dictionnaire des
modules/classes/fonctions/variables du scope global.
I la fonction locals () retourne un dictionnaire des
modules/classes/fonctions/variables du scope courrant.
I les éléments récupérés peuvent être utilisés directement
class A(object):
pass

def foo(o):
print(o)

locs = locals()
locs[’foo’](3)

myclass = locs[’A’]
instance = myclass()
locs[’A’] = type(’B’, [A], {’x’: 0})
instance2 = A()
print(instance2.x)
26/45
Accès reflexifs aux éléments d’un objet

I Le module inspect permet d’aider à l’inspection d’éléments


https://docs.python.org/3/library/inspect.html.
I il est possible d’utiliser la fonction vars (...) pour accéder aux
éléments d’un objet.
I la fonction dir (...) donne l’intégralité des méthodes
appelable depuis un élément.
I la dictionnaire __dict__ permet d’accéder à tout les
attributs explicite d’un élément.
I les méthodes sont des attributs que l’on peut appeler comme
des fonctions (ils sont callable).
I code. inspect permet d’accéder à tout les attributs d’un
élément.
I l’attribut __class__ permet d’accéder à la classe d’un objet.

27/45
Accès reflexifs aux éléments d’un objet
class A(object):
var1_int = None
var2_float = None

def printme(self):
print("I’m an object", self, "in", self.__class__)
print("var1", self.var1, "var2", self.var2)

def update_instance(inst, default):


from inspect import isfunction
for key, val in inst.__class__.__dict__.items():
if not isfunction(val) and not key.startswith(’__’):
varname, vartype = key.split(’_’)
new_val = default[vartype]
setattr(inst, varname, new_val)

a, b = A(), A()
update_instance(a, {’int’: 0, ’float’: 1.0})
update_instance(b, {’int’: 1234, ’float’: 45.3})
a.printme()
b.printme()
28/45
Compilation at run time
I Il est possible de compiler du code lors de l’exécution du code.
I Une fois compilé, le code peut-être directement utilisé.

def gen_getter_for_classvar(cls, attributes):


for name in attributes:
fun_name = "get_{}".format(name)
fun = """def {}(self):
return self.{}
""".format(fun_name, name)
loc, glob = {}, {}
exec(compile(fun, ’<string>’, ’exec’), glob, loc)
setattr(cls, fun_name, loc[fun_name])

class A(object):
x = 0
y = 0

gen_getter_for_classvar(A, ["x", "y"])


# Comment modifier pour l’appliquer a des instances ?

29/45
Typed Python

I Il est possible de typer explicitement les fonctions Python


I Les types sont conservé à l’exécution et ne sont pas analysé
par Python (on peut y accéder par introspection)
I Utilisation par des projets annexes pour founir de la validation
(ex: mypy)
class Point(object):
def __init__(self, x: int, y: int):
self.x = x
self.y = y

def addition(self, other: Point) -> Point:


return Point(self.x + other.x, self.y + other.y)

30/45
Table of Contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

31/45
Tests avec pytest
I Il existe plusieurs framework de test en Python.
I PyTest est framework intéressant et très utilisés dans la
communauté même par de très gros projets
I Les tests reposent sur l’utilisation du mot clef assert .

def test__point_initialisation_without_args():
p = Point()
assert p.x == 5
assert p.y == 5

def test__point_initialisation_with_args():
p = Point(x=6)
assert p.x == 6
assert p.y == 5

p = Point(y=8)
assert p.x == 5
assert p.y == 8

32/45
Table of Contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

33/45
Pile à partir d’une liste

Les questions à se poser ?


I Quelles sont les entitées du système ?
I Quelles sont les méthodes que les entitées doivent gérer ?
I De manière générale, en OO, un diagramme de classe est
souvent pratique à utiliser

34/45
Pile à partir d’une liste
def test_stack_empty():
s = Stack()
assert s.is_empty() is True

def test_stack_push_peek():
s = Stack(); s.push(’a’); s.push(3)
assert s.peek() == 3
assert s.peek() == 3

def test_stack_push_pop():
s = Stack(); s.push(’a’); s.push(3)
assert s.pop() == 3
assert s.peek() == ’a’; assert s.pop() == ’a’
assert s.is_empty() is True

def test_exception():
s = Stack()
with pytest.raises(EmptyStack):
s.peek()
with pytest.raises(EmptyStack):
s.pop()
35/45
Pile à partir d’une liste
class EmptyStack(Exception): pass
class Stack(object):
def __init__(self, l=None):
self.inner_list = list(l) if l else []

def is_empty(self):
return self.inner_list == []

def peek(self):
try:
return self.inner_list[-1]
except IndexError:
raise EmptyStack()

def pop(self):
i = self.peek()
self.inner_list = self.inner_list[:-1]
return i

def push(self, item):


self.inner_list += [item]
36/45
Arbre binaire

I Utilisation du pattern composite

37/45
Arbre binaire
I Utilisation du pattern composite
class TreeElement(object):
def is_leaf(self): pass
def is_node(self): pass

class Node(TreeElement):
def __init__(self, value, left=None, right=None):
self.left = left
self.right = right
self.value = value

def is_leaf(self): ??
def is_node(self): ??

class Leaf(TreeElement):
def __init__(self, value=None):
self.value = value

def is_node(self): ??
def is_leaf(self): ??
38/45
Arbre binaire

Exercices
I Fonction d’affichage infix , prefix et postfix
I Fonction profondeur
I Fonction maximum
I Considérons arbre binaire de recherche, faire un fonction
insertion

39/45
Table of Contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

40/45
Exemples – Ruby
class Bibliotheque
attr_reader :livres

def initialize
@livres = []
end

def ajouter livre


raise "Already exist #{livre}" if @livres.include?
livre
@livres << livre
end

def taille
@livres.length
end

def auteurs
@livres.map { |livre| livre.auteurs }.flatten.uniq
end
end
41/45
Exemples – C#
public class Person {
private string m_name;
public string Name {
get { return m_name; }
set { m_name = value; }
}

public Person() { }

public Person(string name, ushort age) {


this.m_age = age;
this.m_name = name;
}

~Person() {
Console.WriteLine("Destruction");
}

public void SayHi() {


Console.WriteLine("Hello " + this.m_name);
}
} 42/45
Exemples – Smalltalk

43/45
Table of Contents

Programmation Orientée Objet ?

Programmation objet avec Python

Quelques points avancés

Tests unitaires

Structures de données

Exemples

Ressources

44/45
Ressources

Liens intéressants
I Le blog de Sam&Max une référence sur Python en France
(plutôt NSFW)
http://sametmax.com/

45/45

Vous aimerez peut-être aussi