代码之家  ›  专栏  ›  技术社区  ›  fasouto

python attrs中带有额外参数的自定义验证器

  •  1
  • fasouto  · 技术社区  · 7 年前

    我有几个类是使用如下属性定义的:

    from attr import attrs, attrib, validators
    
    @attrs
    class MyClass:
        name = attrib(])
        @name.validator
        def check_length(self, attribute, value):
            if not (3 <= len(value) <= 30):
                raise ValueError("Name must be between 3 and 30 characters")
    
        description = attrib()
        @description.validator
        def check_length(self, attribute, value):
            if not (10 <= len(value) <= 400):
                raise ValueError("Description must be between 10 and 400 characters")
    

    对于一些属性,我需要创建一个验证器来检查数据是否在某个范围内。我想避免重复,所以我可以创建一个自定义验证器,在这里我为min和max传递一些额外的参数,如下所示:

    def range_validator(instance, attribute, value, min_value, max_value):
        if  min_value >= len(value) >= max_value:
            raise ValueError("Must be between {} and {}".format(min_value, max_value))
    

    但是我不知道如何从attrib()内部调用这个验证器来传递额外的参数(min_value和max_value),我的意思是这样做:

    name = attrib(validator=[range_validator(self, 10, 30)])
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   hynek    7 年前

    你可以用 functools.partial :

    def range_validator(instance, attribute, value, min_value, max_value):
        lv = len(value)
        if min_value > lv or lv > max_value:
            raise ValueError("Must be between {} and {}".format(min_value, max_value))
    
    @attrs
    class C:
        x = attrib(validator=partial(range_validator, min_value=10, max_value=30))
    

    或者可以使用闭包:

    def make_range_validator(min_value, max_value):
        def range_validator(instance, attribute, value):
            lv = len(value)
            if min_value > lv or lv > max_value:
                raise ValueError("Must be between {} and {}".format(min_value, max_value))
    
        return range_validator
    
    @attrs
    class C:
        x = attrib(validator=make_range_validator(10, 30))
    

    (请注意,我冒昧地在验证器中修复了一个逻辑错误,您可能也想应用它。:))

    推荐文章