Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Un Downcast de maniére élegante.

8 réponses
Avatar
Wild Cherry
Bonjours,

Voici mon probl=E8me :
J' ai une classe A qui h=E9rite d' une classe B, et un code qui r=E9agit
diff=E9remment selon que la variable soit de type A ou de type B.

J' aimerais cr=E9er une variable de type B =E0 partir d' une variable de
type A, mais d' une mani=E9re non-triviale (=E0 la mani=E9re du
polymorphic_downcast de boost, en C++.)

Est-ce possible?

Merci

8 réponses

Avatar
kaerbuhez
On 20 fév, 16:53, Wild Cherry wrote:
Bonjours,

Voici mon problème :
J' ai une classe A qui hérite d' une classe B, et un code qui réagit
différemment selon que la variable soit de type A ou de type B.


Un bon design objet veut que le comportement spécifique soit
implémenté dans la classe. Ton code au lieu de réagir différemment
devrait donc appeler une méthode sur l'objet qui implémentera ce
comportement spécifique. Par exemple:

#plutot que:
if isinstance(animal, Chien): faire_aboyer(animal)
elif isinstance(animal, Chat): faire_miauler(animal)
else pass # ;-)
#fais ceci:

class Chat
def crie(self): return "miaouw"

class Chien
def crie(self): return "wa wa"

# ...
animal.crie()

J' aimerais créer une variable de type B à partir d' une variable de
type A, mais d' une maniére non-triviale (à la maniére du
polymorphic_downcast de boost, en C++.)


Ca n'a pas de sens dans un langage typé dynamiquement. Dans un langage
statique, il est important de bien faire la différence entre ce qui se
passe au moment de la compilation et ce qui se passe au moment de
l'exécution. Les déclarations de variable servent au moment de la
compilation. Et (down, cross, ....) caster revient à dire au
compilateur: "hé cette variable que j'ai déclaré comme une instance de
telle classe, veux-tu bien la voir maintenant comme une instance de
telle autre classe ?" Attention, le compilateur, qui n'est pas né de
la dernière lune, n'avale ça qu'à certaines conditions, donc ça peut
faire planter ta compilation. Si il est un peu parano (comme javac),
il peut aussi laisser un test dans le binaire qui fait que si ton cast
est "impossible" : tu as "menti" au compilo et l'objet n'est pas du
type annoncé et boum, erreur d'exécution ... Bref, cette longue
digression pour dire que tout ça n'a aucun sens dans un langage
dynamique comme Python puisqu'il n'y a pas de déclaration, ni de
vérification de type. Tu appliques ta méthode sur ton objet point
barre. C'est pour ça qu'on est tellement plus productif. Et rien ne
t'empéche de parsemer ton code de assert si t'as pas confiance ... en
toi, tes collégues, le monde ... ;-)

Voilà ... et une petite suggestion: si tu expliquais ce que tu veux
faire plutôt que de demander comment appliquer une solution ? Les
réponses sont souvent bien plus utiles (pour tout le monde).

Bon courage.

Avatar
Jean-Baptiste renard
Wild Cherry wrote:

Bonjours,

Voici mon problème :
J' ai une classe A qui hérite d' une classe B, et un code qui réagit
différemment selon que la variable soit de type A ou de type B.

J' aimerais créer une variable de type B à partir d' une variable de
type A, mais d' une maniére non-triviale (à la maniére du
polymorphic_downcast de boost, en C++.)

Est-ce possible?

Merci


Ce n'est pas du polymporphic_downcast au sens strict, mais en python un
objet peut changer de classe en utilisant le membre __class__.

Exemple :

class A:
... def plop(self):



... print "A"
...
class B:
... def plop(self):



... print "B"
...
a = A() # On crée un objet de classe A
a.plop()
A



print a.__class__
__main__.A



a.__class__ = B # C'est là qu'on change de classe
a.plop()
B



print a.__class__
__main__.B




l'objet a est maintenant de class B



Avatar
Bruno Desthuilliers
Bonjours,

Voici mon problème :
J' ai une classe A qui hérite d' une classe B, et un code qui réagit
différemment selon que la variable soit de type A ou de type B.


Tu a donc très probablement un problème de conception.

J' aimerais créer une variable de type B à partir d' une variable de
type A, mais d' une maniére non-triviale (à la maniére du
polymorphic_downcast de boost, en C++.)

Est-ce possible?


Plus ou moins - disont qu'il y a des hacks possibles pour obtenir
quelque chose de plus ou moins équivalent - avec leurs inconvénients. En
tout état de cause, c'est une très certainement la mauvaise solution.
Dans la majorité des cas, le dispatch sur le récepteur devrait suffire
et ton code ne devrait pas avoir à se soucier du problème du tout. Dans
la minorité des cas où un simple dispatch ne suffit pas, un double
dispatch devrait résoudre le problème. Il y a quelques recettes et
modules dispos gérant le dispatch multiple...

Merci


Avatar
Bruno Desthuilliers
Bonjours,

Voici mon problème :
J' ai une classe A qui hérite d' une classe B, et un code qui réagit
différemment selon que la variable soit de type A ou de type B.


Tu a donc très probablement un problème de conception.

(snip)


Ah oui, aussi, j'oubliais: si tu nous donnais un exemple un poil plus
concret, on pourrait peut-être t'aider un peu plus concrètement !-)


Avatar
Wild Cherry
Merci pour vos réponses :)

Je ne suis pas un pros du designing objet, rien qu' un étudiant.

Mon petit projet est un jeu de stratégie simpliste :
Une grille, et un panneau latéral.
Le panneau latéral affiche les informations sur l' objet sélectionné.

Il existe deux type d' objet : Squad (une flotte) et Planet.
Or Planet dérive de Squad, car une planéte doit pouvoir contenir des
vaisseaux.

Ces deux classes ne font que retenir les informations sur elle-même,
car je voulais séparer l' affichage (dans un module) de l' etat du jeu
(dans un autre module) et du coeur, qui s' occupe de gérer les
événements (qui sont analysé dans le module affichage).

Une erreur que j' ai faite à été de stocker ces objets dans un
dictionnaire (key : position, value:objet) placé dans le module
Display.

Qu' est-ce que vous me conseilleriez, comme structure?

Si je n' ai pas été très clair, n' hésitez pas à demander ;)
Avatar
Wild Cherry
Ah oui, j' oubliais.

Je me suis aperçu que je n' avait effectivement pas besoin d' un
downcast.
Avatar
bruno.desthuilliers
On 21 fév, 19:35, Wild Cherry wrote:
Merci pour vos réponses :)

Je ne suis pas un pros du designing objet, rien qu' un étudiant.

Mon petit projet est un jeu de stratégie simpliste :
Une grille, et un panneau latéral.
Le panneau latéral affiche les informations sur l' objet sélectionné .

Il existe deux type d' objet : Squad (une flotte) et Planet.
Or Planet dérive de Squad, car une planéte doit pouvoir contenir des
vaisseaux.


Et ? En quoi le fait qu'une planète doive pouvoir contenir des
vaissaux en fait-elle une sorte de flotte ?

Conceptuellement, la relation d'héritage est une relation "est un" -
donc faire dériver Planet de Squad signifie que Planet "est un" Squad.
Ce qui n'est bien évidémment pas le cas. Eventuellement, on peut
imaginer que Planet et Squad dérivent tous les deux de ShipContainer -
ce qui veut dire que Planet "est un" ShipContainer, et que Squad "est
un" ShipContainer. Et encore cela suppose-t'il que la notion de
ShipContainer soit la même pour les deux classes (ce qui peut ou non
être le cas, là c'est toi qui peut savoir)

Si tu a effectivement une interface *et* une implémentation commune
aux deux classes pour cet aspect, ça vaut le coup de factoriser ça
dans une classe ShipContainer. S'il n'y a que l'interface de commune,
comme Python est dynamiquement typé, tu n'a pas besoin que les deux
classes héritent d'une même classe de base - il suffit qu'elles
implémentent effectivement l'interface attendue.

Ces deux classes ne font que retenir les informations sur elle-même,
car je voulais séparer l' affichage (dans un module) de l' etat du jeu
(dans un autre module) et du coeur, qui s' occupe de gérer les
événements (qui sont analysé dans le module affichage).


Bref, un MVC (état du jeu => modèle, affichage => vue, 'coeur qui g ère
les évènements' => controleur).

Une erreur que j' ai faite à été de stocker ces objets


Lesquels ?

dans un
dictionnaire (key : position, value:objet) placé dans le module
Display.

Qu' est-ce que vous me conseilleriez, comme structure?


Fait une recherche sur MVC.

Si je n' ai pas été très clair, n' hésitez pas à demander ;)


Ca ne dit pas en quoi tu croie avoir besoin d'un transtypage (ce qui
était ta question première).

Avatar
Wild Cherry
Conceptuellement, la relation d'héritage est une relation "est un" -
donc faire dériver Planet de Squad signifie que Planet "est un" Squad.
Ce qui n'est bien évidémment pas le cas. Eventuellement, on peut
imaginer que Planet et Squad dérivent tous les deux de ShipContainer -
ce qui veut dire que Planet "est un" ShipContainer, et que Squad "est
un" ShipContainer. Et encore cela suppose-t'il que la notion de
ShipContainer soit la même pour les deux classes (ce qui peut ou non
être le cas, là c'est toi qui peut savoir)

Si tu a effectivement une interface *et* une implémentation commune
aux deux classes pour cet aspect, ça vaut le coup de factoriser ça
dans une classe ShipContainer. S'il n'y a que l'interface de commune,
comme Python est dynamiquement typé, tu n'a pas besoin que les deux
classes héritent d'une même classe de base - il suffit qu'elles
implémentent effectivement l'interface attendue.



Merci du tuyaux. C' est ce que je vais faire : implémenter dans les
deux classes la même interface

Une erreur que j' ai faite à été de stocker ces objets


Lesquels ?



Les objets se trouvant dans la grille (Planéte et Vaisseaux

Ca ne dit pas en quoi tu croie avoir besoin d'un transtypage (ce qui
était ta question première).


J' en avais besoin lors que des vaisseaux 'décollent' d' une planéte :
la flotte présente sur la planéte (l' objet Squad présent dans l'
objet Planet) se désolidarise de l' objet Planet).

Merci à tous pour vos réponses.