Eine einfache Python-Klasse wie diese haben:
class Spam(object):
__init__(self, description, value):
self.description = description
self.value = value
Ich möchte die folgenden Einschränkungen überprüfen:
- "Beschreibung darf nicht leer sein"
- "Wert muss größer als Null sein"
Sollte ich:
1. Daten validieren, bevor ich ein Spam-Objekt erstelle?
2. Daten zur __init__
Methode prüfen ?
3. Erstellen Sie eine is_valid
Methode für die Spam-Klasse und rufen Sie sie mit spam.isValid () auf.
4. Erstellen Sie eine is_valid
statische Methode für die Spam-Klasse und rufen Sie sie mit Spam.isValid auf (Beschreibung, Wert).
5. Daten zur Setterdeklaration prüfen?
6. etc.
Könnten Sie einen gut gestalteten / pythonischen / nicht ausführlichen (auf Klasse mit vielen Attributen) / eleganten Ansatz empfehlen?
self.description = description
ein Unterstrich verwendet werden, dhself._description = description
oder spielt das keine Rolle? Ist dies notwendig oder nur etwas Ähnliches wie Pythons Version von "privaten" Variablen?self.description = …
wird durch Eigenschaft zugewiesen, währendself._description = …
direkt dem zugrunde liegenden Feld zugewiesen wird. Welche während des Baus verwendet werden soll, ist eine Entwurfsentscheidung, aber es ist normalerweise sicherer, immer über die Eigenschaft zuzuweisen. Der obige Code löst beispielsweise eine Ausnahme aus, wenn SieSpam('', 1)
wie gewünscht aufrufen .Wenn Sie die Werte nur beim Erstellen des Objekts überprüfen möchten UND die Übergabe ungültiger Werte als Programmierfehler betrachtet wird, würde ich folgende Aussagen verwenden:
class Spam(object): def __init__(self, description, value): assert description != "" assert value > 0 self.description = description self.value = value
Dies ist ungefähr so kurz wie möglich und dokumentiert deutlich, dass dies Voraussetzungen für die Erstellung des Objekts sind.
quelle
assert value > 0, "value attribute to Spam must be greater than zero"
. Behauptungen sind wirklich Nachrichten an den Entwickler und sollten nicht vom Client-Code abgefangen werden, da sie auf einen Programmierfehler hinweisen. Wenn Sie möchten, dass der Client den Fehler abfängt und behandelt, lösen Sie explizit eine Ausnahme wie ValueError aus, wie in den anderen Antworten gezeigt.def
sollte vor__init__
Sie können einfach Formencode verwenden, es sei denn, Sie möchten unbedingt Ihre eigenen Rollen spielen . Es glänzt wirklich mit vielen Attributen und Schemata (nur Unterklassenschemata) und hat viele nützliche Validatoren eingebaut. Wie Sie sehen, ist dies der Ansatz "Daten vor dem Erstellen eines Spam-Objekts validieren".
from formencode import Schema, validators class SpamSchema(Schema): description = validators.String(not_empty=True) value = validators.Int(min=0) class Spam(object): def __init__(self, description, value): self.description = description self.value = value ## how you actually validate depends on your application def validate_input( cls, schema, **input): data = schema.to_python(input) # validate `input` dict with the schema return cls(**data) # it validated here, else there was an exception # returns a Spam object validate_input( Spam, SpamSchema, description='this works', value=5) # raises an exception with all the invalid fields validate_input( Spam, SpamSchema, description='', value=-1)
Sie könnten die Überprüfungen auch während durchführen
__init__
(und sie mit Deskriptoren | Dekoratoren | Metaklasse vollständig transparent machen), aber ich bin kein großer Fan davon. Ich mag eine saubere Barriere zwischen Benutzereingaben und internen Objekten.quelle
Wenn Sie nur die an den Konstruktor übergebenen Werte überprüfen möchten, können Sie Folgendes tun:
class Spam(object): def __init__(self, description, value): if not description or value <=0: raise ValueError self.description = description self.value = value
Dies wird natürlich niemanden daran hindern, so etwas zu tun:
>>> s = Spam('s', 5) >>> s.value = 0 >>> s.value 0
Der richtige Ansatz hängt also davon ab, was Sie erreichen möchten.
quelle
Sie können versuchen
pyfields
:from pyfields import field class Spam(object): description = field(validators={"description can not be empty": lambda s: len(s) > 0}) value = field(validators={"value must be greater than zero": lambda x: x > 0}) s = Spam() s.description = "hello" s.description = "" # <-- raises error, see below
Es gibt nach
ValidationError[ValueError]: Error validating [<...>.Spam.description='']. InvalidValue: description can not be empty. Function [<lambda>] returned [False] for value ''.
Es ist kompatibel mit Python 2 und 3.5 (im Gegensatz zu
pydantic
) und die Validierung erfolgt jedes Mal, wenn der Wert geändert wird (nicht nur beim ersten Mal im Gegensatz zuattrs
). Es kann den Konstruktor für Sie erstellen, tut dies jedoch nicht standardmäßig, wie oben gezeigt.Beachten Sie, dass Sie möglicherweise
mini-lambda
anstelle der einfachen alten Lambda-Funktionen optional verwenden möchten, wenn die Fehlermeldungen noch einfacher sein sollen (sie zeigen den fehlerhaften Ausdruck an).Einzelheiten finden Sie in der
pyfields
Dokumentation (ich bin übrigens der Autor;))quelle