Pojo喜欢Python中的类

时间:2018-10-21 05:31:41

标签: python class

我想为Python中的User创建一个类似于Pojo的类。每个属性都将涉及一些验证。例如:我不希望有人创建一个年龄为负值的用户。为了达到这个目的,我最终将像下面这样写一个类。

 class User:
        def __init__(self, age):
            self.age = age

        @property
        def age(self):
            return self._age

        @age.setter
        def age(self, value):
            print("Called")
            if value >= 0:
                self._age = 0
            else:
                raise ValueError("Age can't be negative")

看完上面的课后,我有点害怕。原因:

  1. 我的User类将具有大约50'ish属性。我有点不敢想象在这种情况下,这个班级会有多大。

这是在Python中创建此类的正确方法吗?

1 个答案:

答案 0 :(得分:5)

我看不出这是什么笨拙-那里的大多数语言都没有内置的getter / setter验证功能,因此您最终会用您选择的任何语言编写类似的内容-如果要通过验证将所有属性转换为getter / setter对,则必须分别编写它们。

现在,Python是具有非常性质的动态语言,因此可以使用多种方法来减少该过程的冗长性(而不是复杂性)。例如,您可以创建自己的验证器装饰器,使其固定在设置器的顶部,例如:

def validator(cmp, exc):
    def decorator(setter):  # a decorator for the setter
        def wrapper(self, value):  # the wrapper around your setter
            if cmp(value):  # if cmp function returns True, raise the passed exception
                raise exc
            setter(self, value)  # otherwise just call the setter to do its job
        return wrapper
    return decorator

现在您可以定义包含以下内容的getter / setter对:

class User:

    def __init__(self, age):
        self.age = age

    @property
    def age(self):
        return self._age

    @age.setter
    @validator(lambda x: x < 0, ValueError("Age can't be negative"))
    def age(self, value):
        self._age = value

但是,如果只想进行验证,而在设置方法(和获取方法)中不进行其他处理,则可以定义自己的 validating 属性,从而节省很多时间,类似:

class ValidatingProperty(object):

    def __init__(self, prop, cmp, exc):
        self.prop = prop
        self.cmp = cmp
        self.exc = exc

    def __get__(self, instance, owner=None):
        if instance is None:
            return self
        return getattr(instance, self.prop, None)

    def __set__(self, instance, value):
        if self.cmp(value):
            raise self.exc
        setattr(instance, self.prop, value)

    def __delete__(self, instance):
        delattr(instance, self.prop)

现在您可以轻松构建类的getter / setter:

class User:

    age = ValidatingProperty("_age", lambda x: x < 0, ValueError("Age can't be negative"))

    def __init__(self, age):
        self.age = age

如果您需要访问原始属性(假定已设置),而没有环绕包装器,则仍可以使用self._age(或任何“真实”属性)访问原始属性作为第一个参数传递给ValidatingProperty的对象)。您甚至可以单独构建验证器,因此您不必依赖lambda(例如,创建一个IntegerValidator类,该类可让您传递范围进行验证,然后在需要时重复使用)。

另一种选择是将您的班级用户视为成年人,并在文档中解释有效值,如果他们超出该范围,则可能会有错误。如果打算用来自最终用户的数据填充该类,则验证应在收集最终用户数据的那一侧执行(以便最终用户可以从中获得有意义的错误),而不必在模型本身。