用于类实例变量的对象方法链接的 Python 方式 [英] Python way for object method chaining for class instance variables
问题描述
用例:
我有一个接收实例变量(表单域)的表单对象.现在我喜欢使用方法链来验证那里的变量.具有任意方法的示例:
I have a form object which receives instance variables (form fields). Now I like to validate there variables using method chaining. An example with arbitrary methods :
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
这是在 Form 实例变量上创建方法链的 Pythonic 方式吗?
Is this the Pythonic way to create method chaining on the Form instance variables.
推荐答案
是和否.
链接方法调用的 Pythonic 方式正是您所写的:
The Pythonic way to chain method calls is exactly what you've written:
f.validate('a').unspace().len_valid(2)
但是动态访问属性的 Pythonic 方法是不要这样做,除非您必须这样做.如果表单变量存储在 dict
中而不是作为对象的实例变量,那么一切都会变得更简单、更易读.
But the Pythonic way to access attributes dynamically is to not do that unless you have to. If the form variables were stored in a dict
instead of as instance variables of the object, everything would be much simpler and more readable.
即使您确实需要将表单变量作为 fa
而不是 f['a']
访问(例如,因为这是交互式 shell 的一部分,或某些第三方 API 要求),实际上更容易围绕 dict
编写所有代码,并使用您最喜欢的 AttrDict
类(来自 PyPI 或 ActiveState)提供您的用户/第三方 API 的属性样式访问.
Even if you really need the form variables to be accessible as f.a
instead of f['a']
(e.g., because this is part of an interactive shell, or some third-party API requires that), it's actually easier to write all your code around a dict
, and use your favorite AttrDict
class (from PyPI or ActiveState) to provide the attribute-style access for your user/third-party API.
此外,如果您进一步将 Field
对象更改为具有某些方法的值的简单包装器,而不是(实际上)对父项和键的引用,则甚至更简单.
Also, if you further changed the Field
object to be a trivial wrapper around a value with some methods, instead of (in effect) a reference to a parent and a key, it would be even simpler.
此外,如果您像 a_invalid
那样即时生成新属性,您可能希望始终生成它们,而不仅仅是在它们为真时.否则,检查 a
是否有效看起来像这样:
Also, if you generate new attributes on the fly like a_invalid
, you probably want to always generate them, not only when they're true. Otherwise, checking whether a
is valid looks something like this:
try:
avalid = not f.a_invalid
except NameError:
avalid = True
这太令人费解了,但如果您的来电者想避免这种情况,那么唯一的方法就是这样:
That's horribly convoluted, but if your caller wants to avoid that, the only way to do so is something like this:
avalid = not getattr(f, 'a_invalid', False)
这似乎首先违背了为调用者伪造属性的全部目的.
Which seems to defeat the whole purpose of faking attributes for the caller in the first place.
另外,请记住,您必须确保永远不会有名称以 _invalid
结尾的字段.因为你可以在 Python 中为几乎任何东西附加新属性,所以如果你真的想用这种方式做所有事情,为什么要使用 f.a_invalid
而不是 fainvalid
?
Also, keep in mind that you have to make sure that there can never be a field whose name ends with _invalid
. Since you can attach new attributes to almost anything in Python, so if you really do want to do everything this way, why use f.a_invalid
instead of, say, f.a.invalid
?
既然你在评论中问到,一个简单的值的包装看起来像这样:
Since you asked in the comments, a trivial wrapper around a value looks like this:
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
不要让每个字段都到达表单来设置其有效性,只需让表单来做:
Instead of making each field reach up to the Form to set its validity, just make the Form do it:
class Form(object):
…
def valid(self):
return all(field.valid for field in self.fields)
如果你真的需要让 valid
看起来像一个成员变量而不是一个方法,只需使用 @property
.
And if you really need to make that valid
look like a member variable rather than a method, just use @property
.
这篇关于用于类实例变量的对象方法链接的 Python 方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!