J'ai des classes python qui, si simplifiées, ressemblent à: la classe code> la classe code> contient des méthodes (représentées ci-dessus par La méthode que je veux poser sur le sujet est J'aimerais probablement signaler une erreur si un utilisateur essaie de Merci pour votre aide. P> p> dothings code > et domorethets code>) qui implémente la fonctionnalité commune à la fois sur les code> FOO code> Barre code> sous-classes. Les sous-classes CODE> FOO CODE> et BAR CODE> DIREL sont essentiellement dans la manière dont ils interprètent le champ code> code>. (Ci-dessus, ils ne diffèrent que par ce qu'ils montrent lors de l'impression, mais dans mon application actuelle, ils font plusieurs autres choses qui sont plus compliquées.) base code> peut être considéré comme "abstrait": les utilisateurs seulement JAMAIS fonctionner avec FOO code> s et bar code> s. base code> n'existe que comme une maison pour le code commun à ses sous-classes. p> combine code>, ce qui vous permet de prendre deux de ces objets et font une troisième. Parce que foo code> et bar code> interpréter la valeur code> différemment, il n'a pas de sens à combine code> deux sous-classes de différents types: Vous pouvez combine code> deux FOO code> S pour obtenir un foo code> ou deux bar code> s pour obtenir un bar < / code> mais pas un foo code> et a bar code>. Même de sorte que la procédure de combine code> est le idem em> pour toutes les sous-classes, il est donc logique de le faire preuve et défini à un endroit. P> combiner code> deux objets incompatibles, mais je ne vois pas un moyen de le faire sans introduire de laids de dactylecks. Est-ce une bonne pratique de faire cela? Ou devrais-je faire la chose habituelle et ne pas vérifier, documenter le problème et supposer que l'utilisateur n'essaiera pas d'utiliser combiner code> d'une manière qui n'était pas destinée, même si cette utilisation semblait "Réussir" et retourner un objet à ordures au lieu d'élever une erreur? p>
4 Réponses :
Je vois plusieurs approches ici: p>
Ne vérifiez rien et faites confiance à l'utilisateur pour faire la bonne chose. Pourrait être approprié ou dangereux, en fonction de la situation. P> li>
Vérifiez le type. Vous avez raison que ça a l'air moche, mais est la chose la plus facile. P> Li>
ne pas avoir de valeur code> code>, mais nommez-les comme ils sont destinés à avoir ( même que 3, mais les sous-classes ont également un < Code> Propriété Code> Quelle carte accède à identique à 4, mais n'utilisez pas pression code>, température code>) et laissez-les se combiner. p> li>
.value code> à leur variable de valeur "réelle" respective. De cette façon, vous pouvez conserver le. __ init __ () code>, mais le .commine () code> devra être effectué par chaque sous-classe. P> LI>
propriété code>, mais un auto-conçu Descripteur . Dans Cette réponse , je montre comment cela pourrait être fait. P> Li>
ol>
modifier la méthode de combinaison alternativement, alternativement la définition de la classe pour la base à p> puis plus simple, plus agréable, plus simple La méthode de combiner est possible (merci GlglGL) P> def combine(self, b):
if (not(type(self) == type(b))):
raise TypeError("%s cannot combine with %s" %
( type(self), type(b) ))
else:
self.value += b.value
Comparaison __ classe __.__ Nom __ code> est imho très laid. Un bien meilleur moyen serait de comparer type == type (B) code> ou en utilisant isinstance (b, type (auto)) code>.
@glglGL type (auto) == Type (b) code> est toujours vrai comme étant les deux instance code>. isinstance code> a le même problème. D'accord c'est moche mais ...
Aie! N'a pas vu l'OP utilise des classes de style ancien ... alors c'est clair. (J'essaie d'éviter les endroits dans la mesure du possible.) Mais avec isinstance code> il devrait également fonctionner des classes de style ancien (juste testées).
@glglGL Oui, éventuellement la meilleure solution serait de déclarer un objet de base, puis d'utiliser le type (auto) == (B). Modification de ma réponse
Lorsque j'ai travaillé sur le code de production que ne doit pas échouer em>, j'ai utilisé un décorateur en veillant à ce qu'une fonction risquée n'explose pas, se transformera en une boule de feu et souffle tout mon système. try:
some_risky_function()
except Bulletproof:
...
Etant donné que .commune () code> fait conceptuellement des choses complètement différentes selon que les objets sont foo code> ou bar code>, je pense que c'est logique Ne pas avoir la fonction dans le parent abstrait, mais pour le garder dans les classes dérivées. Même si c'est le même code, la combinaison de deux instances de FOO code> serait une opération différente de la combinaison de deux instances de la barre code>. Si le code de .commine () code> est réellement très long, vous pouvez créer une méthode privée dans la classe de base pour effectuer le travail, mais n'appellez-la que des fonctions définies dans la classe dérivée. P >