IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Priorité des opérateurs surchargés dans un cas ambigu


Sujet :

Python

  1. #1
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Par défaut Priorité des opérateurs surchargés dans un cas ambigu
    J'ai créé une classe Matrice et une classe Fraction qui gèrent chacune la surcharge des opérateurs qui leur sont compatibles.
    L'opérateur * est surchargé pour la classe Matrice par les deux méthodes __mul__et __rmul__.
    La première effectue le produit de deux matrices et lève une exception si le second argument n'est pas une matrice.
    La seconde permet de multiplier la matrice par un scalaire de type int ou Fraction.
    Seulement voilà si j'exécute : ma_fraction * ma_matrice ; ça déclenche Fraction.__mul__ et non Matrice.__rmul__ comme escompté. Evidemment Fraction.__mul__ n'est pas conçue pour recevoir une instance de Matrice donc plante.
    (Je précise que si j'exécute: ma_matrice.__rmul__(ma_fraction) ça marche parfaitement, c'est donc bien un problème de priorité)
    Comment faire pour établir une priorité entre les différentes surcharges de l'opérateur * dans ce cas ambigu? (il s'agit de deux classes qui ne sont pas liées par héritage)

    Merci d'avance pour vos réponses!

  2. #2
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par armapython Voir le message
    J'ai créé une classe Matrice et une classe Fraction qui gèrent chacune la surcharge des opérateurs qui leur sont compatibles.
    L'opérateur * est surchargé pour la classe Matrice par les deux méthodes __mul__et __rmul__.
    La première effectue le produit de deux matrices et lève une exception si le second argument n'est pas une matrice.
    La seconde permet de multiplier la matrice par un scalaire de type int ou Fraction.
    Seulement voilà si j'exécute : ma_fraction * ma_matrice ; ça déclenche Fraction.__mul__ et non Matrice.__rmul__ comme escompté. Evidemment Fraction.__mul__ n'est pas conçue pour recevoir une instance de Matrice donc plante.
    (Je précise que si j'exécute: ma_matrice.__rmul__(ma_fraction) ça marche parfaitement, c'est donc bien un problème de priorité)
    Comment faire pour établir une priorité entre les différentes surcharges de l'opérateur * dans ce cas ambigu? (il s'agit de deux classes qui ne sont pas liées par héritage)

    Merci d'avance pour vos réponses!
    Bonjour,

    l'interpréteur Python évalue l'opérateur * de gauche à droite e.g. dans a * b, c'est d'abord a qui est évalué, puis *, puis b et l'interpréteur remplace cette expression par a.__mul__(b)

    si l'opérateur * signifie multiplication pour les nombres et donc est commutatif pour les nombres, ce n'est pas le cas pour les objets.

    ainsi, lorsque vous écrivez ma_fraction * ma_matrice, vous écrivez en réalité ma_fraction.__mul__(ma_matrice).

    de même, lorsque vous écrivez ma_matrice * ma_fraction, vous écrivez en réalité ma_matrice.__mul__(ma_fraction).

    dans le cas des objets, l'opérateur * n'est pas commutatif.

    vous voyez comment tout cela fonctionne ?

    @+.

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 778
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 778
    Par défaut
    Salut,

    Il faut faire comme çà:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    >>> class A:
    ...     def __mul__(self, other):
    ...         print ('A mul')
    ...     def __rmul__(self, other):
    ...         print ('A rmul')
    ...
    >>> class B:
    ...     def __mul__(self, other):
    ...         if not isinstance(other, B):
    ...             print ('B mul route: ', end='')
    ...             return NotImplemented
    ...         print ('B mul')
    ...
    >>> a, b = A(), B()
    >>>
    >>> a * b
    A mul
    >>> b * a
    B mul route: A rmul
    >>> b * b
    B mul
    >>> a * a
    A mul
    >>>
    Dit autrement, b * a est d'abord évalué suivant b.__operator__(a).
    Le "return NotImplemented" force le passage par le __rmul__

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  4. #4
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Salut,
    Le "return NotImplemented" force le passage par le __rmul__

    - W
    je viens d'apprendre une chose intéressante, là.

    @+.

  5. #5
    Membre actif
    Homme Profil pro
    Inscrit en
    Février 2013
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2013
    Messages : 37
    Par défaut
    Alors là je comprend pas ce qu'il se passe...

    Comment "return NotImplemented" 'force la passage par __rmul__', d'abord, et qu' est-ce qu'il se passe lors du print dans la méthode __mul__ de B (c'est quoi ce 'end' ?).

  6. #6
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 778
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 778
    Par défaut
    Citation Envoyé par Delbor Voir le message
    Alors là je comprend pas ce qu'il se passe...

    Comment "return NotImplemented" 'force la passage par __rmul__', d'abord, et qu' est-ce qu'il se passe lors du print dans la méthode __mul__ de B (c'est quoi ce 'end' ?).
    C'est ce que dit la documentation: emulating-numeric-types
    Pour la commande print c'est ici.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  7. #7
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    C'est ce que dit la documentation: emulating-numeric-types
    Pour la commande print c'est ici.

    - W
    Ah oui : __rmul__ --> reflected (swapped) operand multiplication !

    Je ne comprenais pas d'où venait le "r" de __rmul__.


  8. #8
    Membre actif
    Homme Profil pro
    Inscrit en
    Février 2013
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2013
    Messages : 37
    Par défaut
    Ok. Je confondais "return NotImplemented" et "raise NotImplementedError".

    Pour le print j'aurais pu chercher moi-même, mais il était un peu tard

    Merci maestro!

  9. #9
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Par défaut
    à tarball:
    j'ai bien compris que:
    l'interpréteur Python évalue l'opérateur * de gauche à droite e.g. dans a * b, c'est d'abord a qui est évalué, puis *, puis b et l'interpréteur remplace cette expression par a.__mul__(b)
    C'est justement l'intérêt du préfixe r- (__rmul__ , __radd__,etc..) qui permet d'évaluer de droite à gauche quand ça ne marche pas de gauche à droite : dans mon exemple (qui ne marche pas pour l'instant avec les fractions mais marche avec les entiers) j'imagine que ça se passe comme ça:
    Quand je rentre entier*matrice le programme appelle d'abord la méthode __mul__ de l'entier (entier.__mul__(matrice)) qui signale qu'elle ne sait pas quoi faire d'une instance de la classe Matrice, il appelle donc ensuite la méthode __rmul__ de la matrice (matrice.__rmul__(entier)) qui est implémentée pour multiplier un scalaire (entier ou fraction)avec une matrice.

  10. #10
    Candidat au Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Par défaut
    à wiztricks:
    Ca marche parfaitement, merci beaucoup!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Priorité des opérateurs dans un IF
    Par gil38 dans le forum Fortran
    Réponses: 6
    Dernier message: 27/04/2011, 21h31
  2. priorité des opérateurs surchargés
    Par Heimdall dans le forum C++
    Réponses: 8
    Dernier message: 29/03/2011, 09h32
  3. Meilleure solution pour des unit tests? (dans mon cas)
    Par nicdo77 dans le forum Tests et Performance
    Réponses: 2
    Dernier message: 19/08/2007, 19h32
  4. Priorité des opérateurs
    Par neuromencien dans le forum Langage
    Réponses: 3
    Dernier message: 14/05/2007, 17h06
  5. Réponses: 3
    Dernier message: 31/08/2006, 10h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo