带有列表的Python 2描述符

时间:2017-01-18 08:21:54

标签: python descriptor

我想对传递给列表的值进行一些类型检查。

到目前为止,我已经制作了一些像CharField和IntegerField这样的描述符,它们可以很好地工作。

列表描述符我无法工作。

基本字段类:

class Field(object):
    def __init__(self, type_, name, default=None, required=False):
        self.type = type_
        self.name = "_" + name
        self.required = required
        self._default = default

    def __get__(self, instance, owner):
        return getattr(instance, self.name, self.default)

    def __set__(self, instance, value):
        raise NotImplementedError

    def __delete__(self, instance):
        raise AttributeError("Can't delete attribute")

    @property
    def default(self):
        return self._default

    @default.setter
    def default(self, value):
        self._default = value if value else self.type()

我的CharField课程:

class CharField(Field):
    def __init__(self, name, default=None, min_length=0, max_length=0, strip=False):
        super(CharField, self).__init__(unicode, name, default=default)
        self.min_length = min_length
        self.max_length = max_length
        self.strip = strip

    def __set__(self, instance, value):
        if not isinstance(value, (unicode, str)):
            raise TypeError("{} must be a string or unicode".format(self.name))
        if self.strip:
            value = value.strip()
        if self.min_length and len(value) < self.min_length:
            raise ValueError("{} must have a minimum length of {}".format(self.name, self.min_length))
        if self.max_length and len(value) > self.max_length:
            raise ValueError("{} must have a maximum length of {}".format(self.name, self.max_length))
        setattr(instance, self.name, value)

然后是ListField类:

class ListField(Field):
    def __init__(self, name, value_type):
        super(ListField, self).__init__(list, name, default=[])
        self.value_type = value_type

    def __set__(self, instance, value):
        if not isinstance(value, list):
            raise TypeError("{} must be a list".format(self.name))
        setattr(instance, self.name, value)

    def append(self, value):
        if not isinstance(value, self.value_type):
            raise ValueError("Value is list {} must be of type {}".format(self.name, self.value_type))

所以在构造函数中我传递一个名称和一个value_type,这应该确保列表中的每个项目都应该是某种类型。

我该怎么做?

1 个答案:

答案 0 :(得分:0)

感谢您的回答以及我开展的更多研究。

class ListField(Field):
    def __init__(self, name, value_type):
        super(ListField, self).__init__(list, name, default=[])
        self.value_type = value_type

    def __set__(self, instance, value):
        if not isinstance(value, list):
            raise TypeError("{} must be a list".format(self.name))
        setattr(instance, self.name, value)

    def __iter__(self):
        for item in self.default:
            yield item

    def __len__(self):
        return len(self.default)

    def __getitem__(self, item):
        return self.default[item]

    def append(self, value):
        if not isinstance(value, self.value_type):
            raise TypeError("Value is list {} must be of type {}".format(self.name, self.value_type))
        self.default.append(value)

与其他字段不同,可以覆盖此字段而不会抛出错误,但是现在这样做。