Имея простой класс Python вроде этого:
class Spam(object):
__init__(self, description, value):
self.description = description
self.value = value
Я хотел бы проверить следующие ограничения:
- "описание не может быть пустым"
- "значение должно быть больше нуля"
Должен ли я:
1. проверять данные перед созданием объекта спама?
2. проверить данные по __init__
методу?
3. создать is_valid
метод класса Spam и вызвать его с помощью spam.isValid ()?
4. создать is_valid
статический метод класса Spam и вызвать его с помощью Spam.isValid (описание, значение)?
5. Проверить данные в декларации сеттеров?
6. и т. Д.
Не могли бы вы порекомендовать хорошо продуманный / питонический / не подробный (для класса со многими атрибутами) / элегантный подход?
self.description = description
использовать подчеркивание, т.self._description = description
Или это не имеет значения? Это необходимо или просто что-то похожее на версию «частных» переменных в Python?self.description = …
назначается через свойство, тогда какself._description = …
назначается непосредственно базовому полю. Какой из них использовать во время строительства - это выбор дизайна, но обычно безопаснее всегда назначать через свойство. Например, приведенный выше код вызовет исключение, если вы вызоветеSpam('', 1)
, как и должно быть.Если вы хотите только проверить значения при создании объекта И передача недопустимых значений считается ошибкой программирования, я бы использовал утверждения:
class Spam(object): def __init__(self, description, value): assert description != "" assert value > 0 self.description = description self.value = value
Это настолько кратко, насколько вы собираетесь получить, и четко документирует, что это предварительные условия для создания объекта.
источник
assert value > 0, "value attribute to Spam must be greater than zero"
. Утверждения на самом деле являются сообщениями для разработчика и не должны быть пойманы клиентским кодом, поскольку они указывают на ошибку программирования. Если вы хотите, чтобы клиент перехватил и обработал ошибку, тогда явно вызовите исключение, такое как ValueError, как показано в других ответах.def
должен быть вставлен до__init__
Если вы не одержимы собственной идеей, вы можете просто использовать formencode . Он действительно выделяется множеством атрибутов и схем (только схемами подклассов) и имеет множество встроенных полезных валидаторов. Как видите, это подход «проверка данных перед созданием объекта спама».
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)
Вы также можете выполнять проверки во время
__init__
(и делать их полностью прозрачными с помощью дескрипторов | декораторов | метакласса), но я не большой поклонник этого. Мне нравится чистый барьер между пользовательским вводом и внутренними объектами.источник
если вы хотите проверить только те значения, которые переданы конструктору, вы можете сделать:
class Spam(object): def __init__(self, description, value): if not description or value <=0: raise ValueError self.description = description self.value = value
Конечно, это никому не помешает сделать что-то вроде этого:
>>> s = Spam('s', 5) >>> s.value = 0 >>> s.value 0
Итак, правильный подход зависит от того, чего вы пытаетесь достичь.
источник
Вы можете попробовать
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
Это дает
ValidationError[ValueError]: Error validating [<...>.Spam.description='']. InvalidValue: description can not be empty. Function [<lambda>] returned [False] for value ''.
Он совместим с python 2 и 3.5 (в отличие от
pydantic
), и проверка происходит каждый раз, когда значение изменяется (не только в первый раз, а не в первый разattrs
). Он может создать конструктор за вас, но не делает этого по умолчанию, как показано выше.Обратите внимание, что вы можете при желании использовать
mini-lambda
вместо простых старых лямбда-функций, если хотите, чтобы сообщения об ошибках были еще более понятными (они будут отображать ошибочное выражение).Подробности смотрите в
pyfields
документации (я, кстати, автор;))источник