Python 3
Références
Fluent Python
Interfaces
- Protocoles (en Python, hérité de sa définition dans Smalltalk) et duck typing pour la majeur partie des développeurs.
- Abstract Base Classes pour les développeurs de modules et libs (en principe on a pas à en créer).
En Python, “x-like objects”, “x protocol”, et “x interface”, sont compris de la même façon.
Également en Python, ça n’a rien de choquant de ne pas implémenter toutes les méthodes d’une interface dans une classe fille (à vérifier, mais ça peu paraître logique, vu qu’on veut éviter d’écrire du code pour rien; exemple pour rendre un objet itérable et/ou accessible comme si c’était un dict).
Polymorphisme
Coder/designer ses classes de telle sorte que c’est l’interpréteur qui détermine qu’elle méthode exécuter, plutôt que d’utiliser une suite de if/elif avec un isinstance(obj, somecls).
Monkey patching
Peut servir pour implémenter un protocole au moment de l’exécution. Voir aussi le design pattern “Adapter” pour ça.
Note perso : ça peut aussi servir pour les tests, pour mocker une classe d’une lib (à étudier).
Héritage multiple
L’ordre d’héritage peut être retrouvé avec maclass.__mro__
.
Lors d’un héritage multiple, il ne devrait y avoir qu’une seule classe concrète. Les autres peuvent être des mixins ou des interfaces / classes abstraites. Une classe fille ne devrait pas hériter seulement d’une (ou plusieurs) mixin, mais hériter d’au moins une classe concrète ou une interface ou classe abstraite.
Les mixins sont là pour gérer un traitement spécifique. Leur nom devrait inclure
“Mixin” en suffixe (NB une idée un peu hard: empêcher explicitement l’instanciation
de la mixin en faisant en sorte que __init__
raise une bonne exception?).
Il vaut mieux favoriser la composition (utilise une instance de la classe, plutôt qu’en hériter), parce que l’héritage introduit plus de couplage, alors que la composition rend l’application plus flexible.
Python permet aussi la création de classes d’agrégation, qui n’ont généralement aucune implémentation, mais seulement un héritage multiple.
Null pattern
En gros, remplacer return None par quelque chose de plus pertinent, de sorte que
if gotvalue
renvoi False si gotvalue
aurait été None.
Solution :
class MyModel:
# ...
def __bool__(self): # __nonzero__ in py2.x
return True if ... else False
# ...