有一个像这样的简单Python类:
class Spam(object):
__init__(self, description, value):
self.description = description
self.value = value
Run Code Online (Sandbox Code Playgroud)
我想检查以下约束:
我应该:
1.在创建垃圾邮件对象之前验证数据?
2.检查__init__
方法数据?
3. is_valid
在垃圾邮件类上创建一个方法并使用spam.isValid()调用它?
4. is_valid
在Spam类上创建一个静态方法,并使用Spam.isValid(描述,值)调用它?
5.检查制定者声明的数据?
6.等
你能推荐一款设计精良的/ Pythonic /非冗长(具有多种属性的课程)/优雅的方法吗?
Mar*_*tos 90
您可以使用Python 属性分别将规则清晰地应用于每个字段,并在客户端代码尝试更改字段时强制执行它们:
class Spam(object):
def __init__(self, description, value):
self.description = description
self.value = value
@property
def description(self):
return self._description
@description.setter
def description(self, d):
if not d: raise Exception("description cannot be empty")
self._description = d
@property
def value(self):
return self._value
@value.setter
def value(self, v):
if not (v > 0): raise Exception("value must be greater than zero")
self._value = v
Run Code Online (Sandbox Code Playgroud)
任何违反规则的行为都会抛出异常,即使在__init__
函数中也是如此,在这种情况下,对象构造将失败.
更新: 2010年至今的某个时间,我了解到operator.attrgetter
:
import operator
class Spam(object):
def __init__(self, description, value):
self.description = description
self.value = value
description = property(operator.attrgetter('_description'))
@description.setter
def description(self, d):
if not d: raise Exception("description cannot be empty")
self._description = d
value = property(operator.attrgetter('_value'))
@value.setter
def value(self, v):
if not (v > 0): raise Exception("value must be greater than zero")
self._value = v
Run Code Online (Sandbox Code Playgroud)
如果您只想在创建对象时验证值,并且传入无效值被视为编程错误,那么我将使用断言:
class Spam(object):
def __init__(self, description, value):
assert description != ""
assert value > 0
self.description = description
self.value = value
Run Code Online (Sandbox Code Playgroud)
这与您将要获得的内容一样简洁,并且清楚地记录了这些是创建对象的先决条件.
除非你自己动手,否则你可以简单地使用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)
Run Code Online (Sandbox Code Playgroud)
您也可以在期间进行检查__init__
(并使用描述符| decorators | metaclass使它们完全透明),但我不是那个的忠实粉丝.我喜欢用户输入和内部对象之间的干净屏障.
如果您只想验证传递给构造函数的那些值,则可以执行以下操作:
class Spam(object):
def __init__(self, description, value):
if not description or value <=0:
raise ValueError
self.description = description
self.value = value
Run Code Online (Sandbox Code Playgroud)
这当然不会阻止任何人这样做:
>>> s = Spam('s', 5)
>>> s.value = 0
>>> s.value
0
Run Code Online (Sandbox Code Playgroud)
因此,正确的方法取决于您要完成的工作。