Les méthodes magiques en Python

B1a256a3a079cbb663d8073b676620b6?s=47 Bruno
July 22, 2013

Les méthodes magiques en Python

Intérêt et éventail des possibilités ; cas d'utilisation.

Ressources pour en apprendre plus :
http://docs.python.org/2/reference/datamodel.html#special-method-names
http://www.rafekettler.com/magicmethods.html

B1a256a3a079cbb663d8073b676620b6?s=128

Bruno

July 22, 2013
Tweet

Transcript

  1. 2.

    Introduction Attributs spéciaux Classique Spécialisation Exotique La magie dans Python

    variables globales : __file__, __name__ fonction : __main__ attributs spéciaux : __class__, __dict__ méthodes magiques : __add__, __str__, __init__, __hash__
  2. 3.

    Introduction Attributs spéciaux Classique Spécialisation Exotique La magie dans Python

    variables globales : __file__, __name__ fonction : __main__ attributs spéciaux : __class__, __dict__ méthodes magiques : __add__, __str__, __init__, __hash__ ⇒ Exploiter le côté orienté objet du langage
  3. 4.

    Introduction Attributs spéciaux Classique Spécialisation Exotique 1 Introduction 2 Attributs

    spéciaux 3 Classique Surcharge d’opérateur Représentation Conversion de type Allocation 4 Spécialisation Séquences Autres usages 5 Exotique Héritage Descripteurs Accesseurs
  4. 5.

    Introduction Attributs spéciaux Classique Spécialisation Exotique __dict__ attributs de la

    classe dans un dictionnaire class A(object): def __init__(self, **kwargs): self.liste = [1, 2, 3] self.__dict__.update(kwargs)
  5. 6.

    Introduction Attributs spéciaux Classique Spécialisation Exotique __dict__ attributs de la

    classe dans un dictionnaire class A(object): def __init__(self, **kwargs): self.liste = [1, 2, 3] self.__dict__.update(kwargs) >>> a = A(foo="bar", bidule=5) >>> a.__dict__ {"foo": "bar", "bidule": 5, "liste": [1, 2, 3]}
  6. 7.

    Introduction Attributs spéciaux Classique Spécialisation Exotique __class__ classe de l’objet

    class B(object): def __init__(self, nom): self.nom = nom def salue(self): print("Salut " + self.nom) class C(object): def salue(self): print("Bonjour " + self.nom)
  7. 8.

    Introduction Attributs spéciaux Classique Spécialisation Exotique __class__ classe de l’objet

    class B(object): def __init__(self, nom): self.nom = nom def salue(self): print("Salut " + self.nom) class C(object): def salue(self): print("Bonjour " + self.nom) >>> b = B("les parisiens") >>> b.salue() Salut les parisiens >>> b.__class__ = C >>> b.salue() Bonjour les parisiens
  8. 9.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Surcharge d’opérateur On ne

    peut pas définir de nouvel opérateur. Mais on peut tous les surcharger __add__, __sub__, __mul__, __div__, __pow__, __and__, __or__, ... __radd__, ... : paramètres échangés __iadd__, ... : +=, ...
  9. 10.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Surcharge d’opérateur On ne

    peut pas définir de nouvel opérateur. Mais on peut tous les surcharger __add__, __sub__, __mul__, __div__, __pow__, __and__, __or__, ... __radd__, ... : paramètres échangés __iadd__, ... : +=, ... Exprimer naturellement des opérations sur n’importe quel type
  10. 11.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Surcharge d’opérateur >>> from

    numpy import arr >>> arr = array([1, 2, 3]) >>> arr + 2 # __add__ array([3, 4, 5]) >>> 2 * arr # __rmul__ array([2, 4, 6]) >>> arr *= arr; arr # __imull__ array([1, 4, 9]) >>> import picos >>> pb = picos.Problem() >>> x = pb.add_variable("x", 5) >>> x | 1 > 0 # (1x1)-affine constraint: x | |1| > 0 #
  11. 12.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Représentation __str__ jolie représentation

    (à la toString()) __repr__ représentation sérieuse, si possible exécutable ⇒ sérialisation simple __format__, __dir__, __sizeof__
  12. 13.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Représentation __str__ jolie représentation

    (à la toString()) __repr__ représentation sérieuse, si possible exécutable ⇒ sérialisation simple __format__, __dir__, __sizeof__ >>> from numpy import array >>> arr = array([1, 2, 3]) >>> arr # repr(arr) array([1, 2, 3]) >>> print(arr) # str(arr) [1, 2, 3] >>> eval(repr(arr)) array([1, 2, 3])
  13. 14.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Conversion de type De

    nombreuses méthodes vers les types de base : __str__ __bool__ __int__ __long__ __float__ __complex__ __oct__ __hex__ __index__
  14. 15.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Conversion de type De

    nombreuses méthodes vers les types de base : __str__ __bool__ __int__ __long__ __float__ __complex__ __oct__ __hex__ __index__ Appelées par les fonctions str(), int(), ...
  15. 16.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Allocation __new__(cls, [...]) création

    d’un instance __init__(self, [...]) initialisation d’une instance __del__(self) destruction d’une instance
  16. 17.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Allocation Singleton def Singleton(object):

    __instance = None def __new__(cls): if not __instance: __instance = super(Singleton, self). __new__() return __instance
  17. 18.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Allocation Singleton def Singleton(object):

    __instance = None def __new__(cls): if not __instance: __instance = super(Singleton, self). __new__() return __instance def Singleton(object): __etat = {} def __new__(cls): objet = super(Singleton, self).__new__() objet.__dict__ = __etat return object
  18. 19.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Séquences On peut facilement

    implémenter une séquence qui supporte toutes les opérations habituelles. Les méthodes à implémenter dépendent du type de la séquence : immutable → __len__ __getitem__ mutable → immutable + __setitem__ __delitem__ itérable → __iter__ bonus → __reversed__ __contains__ __missing__
  19. 20.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Autres usages pickling :

    __getinitargs__ __getnewargs__ __getstate__ __setstate__ __reduce__ __reduce_ex__ context managers : __enter__(self)__ __exit__(self, ex_type, ex_value, traceback) comme une fonction : __call__(self)
  20. 21.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Héritage Deux méthodes :

    __instancecheck__(self, instance) et __issubclass__(self, subclass) Permettent de redéfinir (une partie de) la résolution des parentés des classes Relativement moins utile pythonic : mieux vaut essayer de faire ce qu’on veut et échouer que tester de manière préventive
  21. 22.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Descripteurs 3 méthodes :

    __get__(self, instance, owner) __set__(self, instance, value) __delete__(self, instance) descripteur = propriété calculée utile pour les conversions, les bases de données, ... ex : distance accessible en mètres et kilomètres class Kilometre(): def __get__(self, instance, owner): return owner.distance / 1000 def __set__(self, instance, value): owner.distance = value * 1000 class Mesure(): def __init__(self, distance): self.distance = float(distance) self.kilometres = Kilometre()
  22. 23.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Accesseurs __getattr__(self, name) quand

    self.name n’existe pas __setattr__(self, name, value) à chaque assignement __delattr__(self, name) lors de del self.name __getattribute__(self, name) toujours appelé __dir__ lister les attributs
  23. 24.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Accesseurs écueils def __setattr__(self,

    name, value): # implementation de base self.__dict__[name] = value # marche aussi super().__setattr__(name, value) # equivalent a self.__setattr__("name", value) # => boucle infinie self.name = value
  24. 25.

    class AccessControl(object): def __init__(self): self.__public__ = self.__dict__ self.__private__ = {}

    def __priv(self, **kwargs): self.__private__.update(kwargs) def __getattribute__(self, name): if name in self.__public__: return self.__public__[name] elif self.__from_inside__() and name in self. __private__: return self.__private__[name] raise AttributeError(name) def __setattr__(self, name, value): if self.__from_inside__() and name in self. __private__: self.__private__ [name] = value else: self.__public__[name] = value
  25. 26.

    def __delattr__(self, name): if name in self.__public__: del self.__public__[name] elif

    self.__from_inside__() and name in self. __private__: del self.__private__ [name] def __from_inside__(self): stack = inspect.stack() parent_locals = stack[2][0].f_locals return "self" in parent_locals and parent_locals ["self"].__class__ == self.__class__
  26. 27.

    def MaClasse(AccessControl): def __init__(self): self.un = "abc" self.__priv(deux="def") def dis_deux(self):

    print(self.deux) >>> a = MaClasse() >>> a.un abc >>> a.deux # AttributeError >>> a.dis_deux() def
  27. 28.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Accesseurs Les méthodes magiques,

    c’est super pour Bien s’intégrer au langage Implémenter finement certains comportements Mettre les mains dans le fonctionnement internes des objets
  28. 29.

    Introduction Attributs spéciaux Classique Spécialisation Exotique Accesseurs Les méthodes magiques,

    c’est super pour Bien s’intégrer au langage Implémenter finement certains comportements Mettre les mains dans le fonctionnement internes des objets Merci pour votre attention ! Des questions ? Slides dispos sur https://speakerdeck.com/brunal/methodes-magiques