2016-06-28 10 views
2

Ich arbeite durch ein mechanisches System (z. B. eine einfache Schrägverzahnung) und möchte verhindern, dass Benutzer Werte zuweisen, die nicht in einer zugeordneten Aufzählung enthalten sind. Ich bin neu in Aufzählungen und ‚pythonic‘ nähert sich, diese Frage zu beantworten ... so meine Anfrage ist zweifach:Verwenden von Enums zum Überprüfen von Attributen einer Klasse/Instanz in Python

  1. Ist es sinnvoller in Python Eingabefehler passieren zu lassen und nachfolgenden Code verwenden, um die Folgen zu verwalten ?
  2. Sollte die Enum in der Klasse definiert werden, die es verwendet? Ich beabsichtige nicht, dass dieses Enum an anderer Stelle verfügbar ist ... Ich fühle mich komisch, wenn ich es am Anfang meiner Akte hängen lasse.

Hier ist der Code:

HAND = Enum('HAND', ['LH', 'RH']) 


class HelicalGear(Gear): 
    def __init__(self, hand): 
     self.type_ = 'Helical' 
     self.hand = hand 

    @property 
    def hand(self): 
     return self._hand 

    @hand.setter 
    def hand(self, hand): 
     if not hand: 
      raise ValueError("Gear hand definition required") 
     elif hand not in [e.name for e in HAND]: 
      raise ValueError("Gear hand must be LH or RH") 

     self._hand = hand 

Antwort

3
  1. Fehlerbehandlung sollte möglichst nahe an den Ursprung des Fehlers wie möglich passieren. Egal ob Benutzer Daten eingeben oder Funktionen/Klassen Daten akzeptieren, diese Daten sollten sofort überprüft und bearbeitet werden.

  2. Wo Sie die Enum definieren, liegt ganz bei Ihnen, aber ich neige dazu, sie auf der obersten Ebene aus mehreren Gründen zu verlassen:

    • Andere Code, die sie verwenden muss:
      somemod.HAND.LH oder
      somemod.HelicalGear.HAND.LH ?
    • Was passiert, wenn Sie später eine andere Klasse mit Rechts- und Linkshändern erstellen?

Minor Korrektur: Ihre __init__ self._hand Einstellung werden sollte. Wie MisterMiyagi kommentierte: Verwendung von hand anstelle von _hand hat den Vorteil der Fehlererkennung Code in hand.setter.

In Ihrem setter Code Ich möchte etwas tun:

@hand.setter 
def hand(self, hand): 
    if hand in HAND: 
     # already an Enum, pass 
     pass 
    elif hand in HAND.__members__: 
     # it's the name of a hand 
     hand = HAND[hand] 
    else: 
     # numeric? 
     hand = HAND(hand) 
     # if not, a ValueError will be raised: 
     # `ValueError: 0 is not a valid Hand` 
    # save the Enum value 
    self._hand = hand # or hand.value or hand.name depending on what you want 
         # returned when HelicalGear.hand is accessed 
+0

'__init__' setzt implizit' self._hand' über 'hand.setter'. Die Verwendung des Setter hat den Vorteil, die Typprüfung hinzuzufügen. – MisterMiyagi

+0

Danke für die schnelle Rückmeldung! Sehr hilfreich! –

+0

@MisterMiyagi: Ah, genau du bist! Danke, dass du das verstanden hast. –

1

Es gibt keine Antwort angemessen im Allgemeinen - es hängt wirklich davon ab, wie Sie Ihre Objekte verwenden.

Ein wichtiges Konzept von Python ist die Duck-Typisierung - das heißt, ob ein Objekt geeignet ist, wird durch seine Features definiert, nicht durch seinen Typ. In Ihrem Beispiel denken Sie darüber nach, was eine Enumeration ist: eine Zuordnung eines Namens zu einer Ganzzahl.

Also, sollte man erzwingen, dass Benutzer den Enum-Eintrag bereitstellen? Oder akzeptiere den Namen genauso wie in deinem Code? Wenn der folgende Code nur für den Enum-Wert gilt, würde das einfache Bereitstellen dieses Werts (z. B. 1 für LH) ebenfalls funktionieren.

Ich persönlich ziehe implizite Typprüfung in Client-Code zu tun, die tatsächlich Daten [1] verwendet, nicht eine strenge Typprüfung durch Interface-Code, der nur speichert Werte. Das spätere erfordert, explizit etwas zu schreiben, das implizit später sowieso ausgeführt wird. Das bedeutet, dass Sie Ihren Typ immer auf dem neuesten Stand halten müssen mit beliebigen Client-Code.

Also sollte die Frage nicht sein "bringe ich einen Fehler auf falsche Eingabe?" aber "kann ich falsche Eingaben erkennen, ohne sie zu benutzen?". Wenn Sie das später mit "Ja" beantworten, dann ist es einfach mehr praktisch, um einen Fehler sofort zu erhöhen. Wenn Sie es mit "nicht beantworten, die Enum kann außerhalb meiner Klasse anwendbar sein" dann kostet zu schnell auf Fehler zu erhöhen kostet Sie viel Flexibilität.


[1] Die Ausnahme ist Eingabebereinigung. Wenn Sie zum Beispiel eine Eingabe an eine eval senden, sollten Sie besser als Nachsicht sein.

+0

Minor nit: 'Enum's Start bei' 1', nicht '0'. –

+0

@EthanFurman So identifiziert man python3-Neulinge. ^^ Danke für den Hinweis, habe mich immer noch nicht daran gewöhnt, mich an die neuen Spielzeuge zu gewöhnen. – MisterMiyagi

+0

Wenn Sie früher oder später mit 'Enum' spielen möchten, schauen Sie sich den Backport an: https://pypi.python.org/pypi/enum34. –

Verwandte Themen