2017-01-18 2 views
2

Ich möchte einige Typenprüfung auf Werte, die in eine Liste übergeben werden.Python 2-Deskriptoren mit Liste

Bis jetzt habe ich einige Deskriptoren wie CharField und IntegerField gemacht, die perfekt funktionieren.

Der Liste-Deskriptor kann ich nicht arbeiten, obwohl.

Die Basisfeld Klasse:

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() 

Meine CharField Klasse:

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) 

Und dann der Listfield-Klasse:

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)) 

So in den Konstruktor übergeben ich einen Namen und eine value_type, das sicherstellen soll, dass jedes Element in der Liste einen bestimmten Typ hat.

Wie soll ich das können?

+2

Was ist das Problem mit Ihrer aktuellen Implementierung? – hansaplast

+0

Können Sie den Typ eines Elements der Werteliste mit dem Befehl 'isinstance (element, self.value_type) 'vergleichen? Wenn ja, können Sie hinzufügen: 'wenn nicht alle ([isinstance (element, self.value_type) für Element in Wert]): raise TypeError (" {} elements type muss {} "sein format (self.name, self. value_type)) ' – Frodon

+0

@hansaplast Die Typprüfung funktioniert nicht, wenn ein Wert an die Liste angehängt wird –

Antwort

0

Dank Ihrer Antworten und einige weitere Forschung habe ich es zur Arbeit.

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) 

Im Gegensatz zu den anderen Bereichen, kann dies ein, ohne dass ein Fehler ausgelöst außer Kraft gesetzt werden wird, aber jetzt dies tun wird.

Verwandte Themen