用例:
我有一个表单对象,它接收实例变量(表单字段)。现在我想使用方法链来验证变量。使用任意方法的示例:
class Field(object):
def __init__(self, form, name):
self.form = form
self.name = name
def unspace(self):
setattr(self.form, self.name, getattr(self.form, self.name).replace(' ',''))
return self
def len_valid(self, length):
if len(getattr(self.form, self.name)) < length :
setattr(self.form, self.name + '_invalid', True)
self.form.valid = False
return self
class Forms(object):
def __init__(self):
self.valid = True
def validate(self, name):
return Field(self,name)
f = Forms() # create the form with some data
f.a = 'J o Hn '
f.b = ' Too L o n g'
f.validate('a').unspace().len_valid(2)
f.validate('b').unspace().len_valid(5)
RESULT :
f.a : 'JoHn'
f.a_invalid : True
f.b : 'TooLong'
f.valid : False
这是Pythonic在Form实例变量上创建方法链的方法吗?
答案 0 :(得分:4)
是和否。
链式方法调用的Pythonic方法正是你所写的:
f.validate('a').unspace().len_valid(2)
但是动态访问属性的Pythonic方法是不要这样做,除非你必须这样做。如果表单变量存储在dict
而不是对象的实例变量中,那么一切都会更简单,更易读。
即使您确实需要将表单变量作为f.a
而不是f['a']
进行访问(例如,因为这是交互式shell的一部分,或者某些第三方API需要),所以实际上更容易在dict
周围编写所有代码,并使用您最喜欢的AttrDict
类(来自PyPI或ActiveState)为您的用户/第三方API提供属性样式访问。
此外,如果您使用某些方法进一步将Field
对象更改为值的简单包装,而不是(实际上)对父级和键的引用,则更简单。 / p>
此外,如果您像a_invalid
那样动态生成新属性,您可能希望始终生成它们,而不仅仅是在它们为真时。否则,检查a
是否有效看起来像这样:
try:
avalid = not f.a_invalid
except NameError:
avalid = True
这是非常令人费解的,但如果你的来电者想要避免这种情况,那么这样做的唯一方法就是这样:
avalid = not getattr(f, 'a_invalid', False)
这似乎首先打败了为调用者伪造属性的整个目的。
另外,请记住,您必须确保永远不会有名称以_invalid
结尾的字段。既然您可以将新属性附加到Python中的任何内容中,那么如果您确实希望以这种方式执行所有操作,那么为什么要使用f.a_invalid
而不是f.a.invalid
?
由于您在评论中提到,值周围的值很简单:
class Field(object):
def __init__(self, value):
self.value = value
self.valid = True
def unspace(self):
self.value = self.value.replace(' ', '')
return self
def len_valid(self, length):
if len(self.value) < length:
self.valid = False
return self
不要让每个字段都达到表单来设置其有效性,只需让表单执行:
class Form(object):
…
def valid(self):
return all(field.valid for field in self.fields)
如果你真的需要让valid
看起来像一个成员变量而不是一个方法,那就使用@property
。