Je n'ai pas très bien compris comment python comprends quand il faut qu'il utilise une méthode spéciale. Est-ce-que __iadd__ est une méthode spéciale? Pourtant J'ai essayé de changer de change __iadd__ en __azadd__ par exemple et le code fonctionne toujours. Pourquoi? Est-ce-que python a compris qu'il faut activer cette méthode ou c'est autre chose?
class Duree:
"""Classe contenant des durées sous la forme d'un nombre de minutes
et de secondes"""
def __init__(self, min=0, sec=0):
"""Constructeur de la classe"""
self.min = min # Nombre de minutes
self.sec = sec # Nombre de secondes
def __str__(self):
"""Affichage un peu plus joli de nos objets"""
return "{0:02}:{1:02}".format(self.min, self.sec)
def __add__(self, objet_a_ajouter):
"""L'objet à ajouter est un entier, le nombre de secondes"""
nouvelle_duree = Duree()
# On va copier self dans l'objet créé pour avoir la même durée
nouvelle_duree.min = self.min
nouvelle_duree.sec = self.sec
# On ajoute la durée
nouvelle_duree.sec += objet_a_ajouter
# Si le nombre de secondes >= 60
if nouvelle_duree.sec >= 60:
nouvelle_duree.min += nouvelle_duree.sec // 60
nouvelle_duree.sec = nouvelle_duree.sec % 60
# On renvoie la nouvelle durée
return nouvelle_duree
def __radd__(self, objet_a_ajouter):
"""Cette méthode est appelée si on écrit 4 + objet et que
le premier objet (4 dans cet exemple) ne sait pas comment ajouter
le second. On se contente de rediriger sur __add__ puisque,
ici, cela revient au même : l'opération doit avoir le même résultat,
posée dans un sens ou dans l'autre"""
return self + objet_a_ajouter
def __iadd__(self, objet_a_ajouter):
"""L'objet à ajouter est un entier, le nombre de secondes"""
# On travaille directement sur self cette fois
# On ajoute la durée
self.sec += objet_a_ajouter
# Si le nombre de secondes >= 60
if self.sec >= 60:
self.min += self.sec // 60
self.sec = self.sec % 60
# On renvoie self
return self
heure = Duree(37, 49)
print(heure)
# test de add
heure = heure + 60
print(heure)
# test de add mais sur une autre variable
d2 = heure.__add__(300)
print(d2)
# test de radd
heure = 60 + heure
print(heure)
# test de iadd
heure += 60
print(heure)
Echo293 a écrit:
> Donc quelle est l'utilité de la définir? Est-ce pareil pour les méthodes de comparaison ainsi que toutes les autres?
On peut prendre l'exemple des listes de Python : la méthode __iadd__ y est utilisée pour modifier la liste en-place lors d'un +=, comme on le voit dans la méthode suivante :
>>> a = b = []
>>> a += [0, 1, 2]
>>> a
[0, 1, 2]
>>> b
[0, 1, 2]
Cela ne serait pas possible avec juste la méthode __add__ (à moins de casser le fonctionnement normal de l'opération +), voilà le résultat qu'on aurait sans __iadd__ :
>>> a = b = []
>>> a = a + [0, 1, 2]
>>> a
[0, 1, 2]
>>> b
[]
Comme dit par thelinekioubeur cela permet donc d'avoir des différences de comportement entre les deux opérations (différences minimes généralement car il s'agit quand même d'une opération similaire).
D'accord, merci à vous deux ! Donc on peut définir cette méthode spéciale pour qu'elle ait un comportement différent, et c'est pareil pour les autres méthodes, c'est bien cela? Merci!
Ça dépend de la façon de voir les choses.
La modification de la liste courante permet de gagner en performances parce qu'il n'y a pas besoin d'allouer un nouvel objet.
Ce serait aussi possible avec update, mais ça n'a pas la même lisibilité qu'un opérateur +.
En fait __iadd__ et extend font strictement la même chose sur les listes, c'est ça la bêtise je pense.
Au final j'utilise toujours extend et jamais +=. Car quand je fais += je m'attend justement à ce que ça alloue un nouvel objet, comme sur les autres types de base (qui sont certes imutables, je ne vois pas d'autres cas que list où le + est défini sur un mutable).
Edit: ah ya aussi bytearray, et comme pour les listes __iadd__ et extend font la même chose
- Edité par thelinekioubeur 4 août 2020 à 15:33:46
extenden effet.
Mais en fait c'est le comportement de base sur tous les types mutables, oui, le i dans le nom de la méthode spéciale est d'ailleurs là pour in-place.
Tu auras la même chose sur les sets avec &=, |=, ^= et -=.
En dehors des builtins, tu auras aussi ce comportement sur les types mutables de la bibliothèque standard, collections.Counter par exemple. C'est le comportement normal et voulu.
Globalement la différence est que l'une est une méthode et l'autre un opérateur, tu passeras plus facilement une méthode en paramètre par exemple.
Le fait que += soit un opérateur d'assignation implique aussi quelques différences à l'usage : il faut que ce qui soit à gauche soit une cible d'assignation valide (pas un appel de fonction par exemple), et comme il s'agit d'une redéfinition de variable ça peut poser problème pour les variables non locales.
Oui après on peut très bien passer __iadd__ en paramètre.
Ça me semble quand même étrange comme choix. En principe on les méthodes qui modifient l'objet sur place, comme list.extend, ne renvoient rien, ou en tout cas pas self. Et list.__iadd__ fait exception car étant une méthode d'opérateur, elle doit forcément renvoyer qqchose...
Aussi on pourrait ptet trouver des usecase où on veut forcément un nouvel objet, où l'on devra faire "a = a + b", et là ça fait bizarre de ne pas utiliser +=
Mais passer x.__iadd__ en paramètre non, personne ne fait ça. Les méthodes spéciales n'ont normalement jamais besoin d'être appelées directement.
Quant à vouloir travailler sur un nouvel objet, il y a aussi la solution de faire une copie au préalable.
Mais oui, cela peut amener à des comportements perturbants.
thelinekioubeur a écrit:
> En principe on les méthodes qui modifient l'objet sur place, comme list.extend, ne renvoient rien
C'est vrai pour les méthodes standard oui, mais les opérateurs sont un peu différents.
thelinekioubeur a écrit:
> On voit parfois des trucs genre "map(a.getitem, foo)".
Je n'ai jamais vu, mais je trouve ça beaucoup moins élégant que operator.itemgetter par exemple (operator.itemgetter(foo)(a)).
Mais oui, les appels à operator sont plus courant, par contre il faut préciser les opérandes (comme avec le partial ici). Je ne crois pas avoir déjà vu le cas que tu cites.
× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
× Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique
entwanne — @entwanne — Un zeste de Python — La POO en Python — Notions de Python avancées — Les secrets d'un code pythonique