类实例变量的对象方法链接的Python方法

类实例变量的对象方法链接的Python方法,python,python-2.7,Python,Python 2.7,用例: 我有一个表单对象,它从表单字段接收实例变量。现在我喜欢使用方法链接来验证这些变量。使用任意方法的示例: 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.

用例:

我有一个表单对象,它从表单字段接收实例变量。现在我喜欢使用方法链接来验证这些变量。使用任意方法的示例:

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
这是在表单实例变量上创建方法链接的python方法吗

是和否

Pythonic方法链方法调用正是您所写的:

f.validate('a').unspace().len_valid(2)  
但是动态访问属性的python方法是不这样做,除非您必须这样做。如果表单变量存储在dict中,而不是作为对象的实例变量,那么一切都会变得更简单、更可读

即使您确实需要表单变量作为f.a而不是f['a']进行访问,例如,因为这是交互式shell的一部分,或者某些第三方API要求这样做,实际上围绕dict编写所有代码更容易,并使用PyPI或ActiveState中您最喜欢的AttrDict类为您的用户/第三方API提供属性样式访问

此外,如果您进一步将Field对象更改为使用某些方法围绕值的普通包装器,而不是实际上对父对象和键的引用,则会更简单

此外,如果您像“无效”一样动态生成新属性,您可能希望始终生成它们,而不仅仅是在它们为真时。否则,检查a是否有效如下所示:

try:
    avalid = not f.a_invalid
except NameError:
    avalid = True
avalid = not getattr(f, 'a_invalid', False)
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
这是非常复杂的,但是如果你的来电者想要避免这种情况,唯一的方法就是这样:

try:
    avalid = not f.a_invalid
except NameError:
    avalid = True
avalid = not getattr(f, 'a_invalid', False)
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
这似乎在一开始就挫败了为调用者伪造属性的全部目的

此外,请记住,您必须确保不存在名称以_invalid结尾的字段。既然在Python中几乎可以将新属性附加到任何东西上,那么如果您真的希望以这种方式执行所有操作,为什么要使用f.a_invalid而不是f.a.invalid呢

由于您在注释中提出了问题,因此围绕值的一个普通包装器如下所示:

try:
    avalid = not f.a_invalid
except NameError:
    avalid = True
avalid = not getattr(f, 'a_invalid', False)
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
如果您真的需要使该有效值看起来像一个成员变量而不是一个方法,只需使用@property。

是和否

Pythonic方法链方法调用正是您所写的:

f.validate('a').unspace().len_valid(2)  
但是动态访问属性的python方法是不这样做,除非您必须这样做。如果表单变量存储在dict中,而不是作为对象的实例变量,那么一切都会变得更简单、更可读

即使您确实需要表单变量作为f.a而不是f['a']进行访问,例如,因为这是交互式shell的一部分,或者某些第三方API要求这样做,实际上围绕dict编写所有代码更容易,并使用PyPI或ActiveState中您最喜欢的AttrDict类为您的用户/第三方API提供属性样式访问

此外,如果您进一步将Field对象更改为使用某些方法围绕值的普通包装器,而不是实际上对父对象和键的引用,则会更简单

此外,如果您像“无效”一样动态生成新属性,您可能希望始终生成它们,而不仅仅是在它们为真时。否则,检查a是否有效如下所示:

try:
    avalid = not f.a_invalid
except NameError:
    avalid = True
avalid = not getattr(f, 'a_invalid', False)
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
这是非常复杂的,但是如果你的来电者想要避免这种情况,唯一的方法就是这样:

try:
    avalid = not f.a_invalid
except NameError:
    avalid = True
avalid = not getattr(f, 'a_invalid', False)
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
这似乎在一开始就挫败了为调用者伪造属性的全部目的

此外,请记住,您必须确保不存在名称以_invalid结尾的字段。既然在Python中几乎可以将新属性附加到任何东西上,那么如果您真的希望以这种方式执行所有操作,为什么要使用f.a_invalid而不是f.a.invalid呢

由于您在注释中提出了问题,因此围绕值的一个普通包装器如下所示:

try:
    avalid = not f.a_invalid
except NameError:
    avalid = True
avalid = not getattr(f, 'a_invalid', False)
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

如果你真的需要让它看起来像一个成员变量而不是一个方法,只需使用@property即可。

这不是一个直接的答案,但是:这些东西必须是attributes实例变量,而不仅仅是dict的成员,这样你就可以删除所有setattr/getattr内容并编写简单的,直接代码?你把这条路弄得太复杂了。照@abarnert说的做,然后把所有的东西都放在dict中。这不是一个直接的答案,但是:这些东西必须是attributes实例变量,而不仅仅是dict的成员,这样你就可以删除所有setattr/getattr内容,编写简单、直接的代码了吗?你这样做太复杂了。按照@abarnert所说的去做,把所有的东西都放在一个dict中。或者你可以只使用一个现有的表单验证库。@Marcin:表单验证是表单wizzard的一部分。这就是我没有使用验证库的原因。@abarnert。谢谢你的评论。对于我的Jinja模板,我使用带有_无效的名称,因为我可以很容易地删除它们。你能给我举个小包装的例子吗。顺便说一句:我从听写改为
实例变量,使其更具可读性。根据您的建议,如AttrDict,我将再试一次。@voscausa我不知道为什么不使用现有库来完成此任务。@Marcin:当然,除了您可能希望使用具有自己的验证系统的现有表单向导库之外,这样您就不需要单独的表单验证库了。:或者您可以只使用现有的表单验证库。@Marcin:表单验证是表单wizzard的一部分。这就是我没有使用验证库的原因。@abarnert。谢谢你的评论。对于我的Jinja模板,我使用带有_无效的名称,因为我可以很容易地删除它们。你能给我举个小包装的例子吗。顺便说一下:我从dict切换到实例变量,以使其更具可读性。根据您的建议,如AttrDict,我将再试一次。@voscausa我不知道为什么不使用现有库来完成此任务。@Marcin:当然,除了您可能希望使用具有自己的验证系统的现有表单向导库之外,这样您就不需要单独的表单验证库了。: