7
votes

Python - Typechecking OK quand une erreur ne serait pas lancée autrement?

J'ai des classes python qui, si simplifiées, ressemblent à: xxx

la classe la classe contient des méthodes (représentées ci-dessus par dothings et domorethets ) qui implémente la fonctionnalité commune à la fois sur les FOO Barre sous-classes. Les sous-classes FOO et BAR DIREL sont essentiellement dans la manière dont ils interprètent le champ . (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 peut être considéré comme "abstrait": les utilisateurs seulement JAMAIS fonctionner avec FOO s et bar s. base n'existe que comme une maison pour le code commun à ses sous-classes.

La méthode que je veux poser sur le sujet est combine , ce qui vous permet de prendre deux de ces objets et font une troisième. Parce que foo et bar interpréter la valeur différemment, il n'a pas de sens à combine deux sous-classes de différents types: Vous pouvez combine deux FOO S pour obtenir un foo ou deux bar s pour obtenir un bar < / code> mais pas un foo et a bar . Même de sorte que la procédure de combine est le idem pour toutes les sous-classes, il est donc logique de le faire preuve et défini à un endroit.

J'aimerais probablement signaler une erreur si un utilisateur essaie de combiner 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 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?

Merci pour votre aide.


0 commentaires

4 Réponses :


3
votes

Je vois plusieurs approches ici:

  1. Ne vérifiez rien et faites confiance à l'utilisateur pour faire la bonne chose. Pourrait être approprié ou dangereux, en fonction de la situation.

  2. Vérifiez le type. Vous avez raison que ça a l'air moche, mais est la chose la plus facile.

  3. ne pas avoir de valeur , mais nommez-les comme ils sont destinés à avoir ( pression , température ) et laissez-les se combiner.

  4. même que 3, mais les sous-classes ont également un < Code> Propriété Quelle carte accède à .value à leur variable de valeur "réelle" respective. De cette façon, vous pouvez conserver le. __ init __ () , mais le .commine () devra être effectué par chaque sous-classe.

  5. identique à 4, mais n'utilisez pas propriété , mais un auto-conçu Descripteur . Dans Cette réponse , je montre comment cela pourrait être fait.


0 commentaires

2
votes

modifier la méthode de combinaison xxx pré>

alternativement, alternativement la définition de la classe pour la base à p> xxx pré>

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


4 commentaires

Comparaison __ classe __.__ Nom __ est imho très laid. Un bien meilleur moyen serait de comparer type == type (B) ou en utilisant isinstance (b, type (auto)) .


@glglGL type (auto) == Type (b) est toujours vrai comme étant les deux instance . isinstance 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 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



0
votes

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:
...


0 commentaires

0
votes

Etant donné que .commune () fait conceptuellement des choses complètement différentes selon que les objets sont foo ou bar , 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 serait une opération différente de la combinaison de deux instances de la barre . Si le code de .commine () 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.


0 commentaires