$30 off During Our Annual Pro Sale. View Details »

Les méthodes magiques en Python

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

Bruno

July 22, 2013
Tweet

Other Decks in Programming

Transcript

  1. Introduction Attributs spéciaux Classique Spécialisation Exotique
    Les méthodes magiques en Python
    Bruno Cauet
    [email protected]
    22 juillet 2013

    View Slide

  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__

    View Slide

  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

    View Slide

  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

    View Slide

  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)

    View Slide

  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]}

    View Slide

  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)

    View Slide

  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

    View Slide

  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__, ... : +=, ...

    View Slide

  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

    View Slide

  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 #

    View Slide

  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__

    View Slide

  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])

    View Slide

  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__

    View Slide

  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(), ...

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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__

    View Slide

  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)

    View Slide

  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

    View Slide

  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()

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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__

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide