2017-01-18 5 views
2

Я хотел бы сделать некоторую проверку типов значений, которые передаются в список.Дескрипторы Python 2 со списком

До сих пор я сделал некоторые дескрипторы, такие как 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, который должен убедиться, что каждый элемент в списке должен иметь определенный тип.

Как я могу это сделать?

+2

В чем проблема с вашей текущей реализацией? – hansaplast

+0

Можете ли вы сравнить тип элемента списка значений с помощью команды 'isinstance (element, self.value_type)'? Если да, то вы можете добавить: 'if not all ([isinstance (element, self.value_type) для значения элемента]): raise TypeError (" {} тип элементов должен быть {} ". Format (self.name, self. value_type)) ' – Frodon

+0

@hansaplast Проверка типа не работает при добавлении значения в список –

ответ

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) 

В отличие от других полей, это один может быть отменено без ошибки броска, но теперь это будет делать.

Смежные вопросы