2011-04-07 7 views
6

Estoy intentando construir una clase que herede métodos de la lista de Python, pero también hace algunas cosas adicionales en la parte superior ... probablemente sea más fácil simplemente mostrar el código en este momento ...Emulando el método list.insert() como una subclase de la lista de Python

class Host(object): 
    """Emulate a virtual host attached to a physical interface""" 
    def __init__(self): 
    # Insert class properties here... 
    pass 

class HostList(list): 
    """A container for managing lists of hosts""" 
    def __init__(self): 
     self = [] 

    def append(self, hostobj): 
     """append to the list...""" 
     if hostobj.__class__.__name__ == 'Host': 
      self.insert(len(self), hostobj) 
     else: 
      _classname = hostobj.__class__.__name__ 
      raise RuntimeError, "Cannot append a '%s' object to a HostList" % _classname 

Mi problema es el siguiente ... si quiero realizar el mismo tipo de pruebas de admisión de objetos en insert() como hice en append(), no puedo encontrar una manera de codificar la nuevos métodos sin sacrificar el soporte para un método de expansión de lista (es decir, list.append(), list.insert(), o list.extend()). Si trato de apoyarlos a todos, termino con bucles recursivos. ¿Cuál es la mejor forma de solucionar este problema?

EDIT: Me tomó la sugerencia sobre la subclasificación collections.MutableSequence lugar de la lista de Python()

El código resultante ... publicar aquí por si acaso, que ayuda a alguien ...

from collections import MutableSequence 
class HostList(MutableSequence): 
    """A container for manipulating lists of hosts""" 
    def __init__(self, data): 
     super(HostList, self).__init__() 
     if (data is not None): 
      self._list = list(data) 
     else: 
      self._list = list() 

    def __repr__(self): 
     return "<{0} {1}>".format(self.__class__.__name__, self._list) 

    def __len__(self): 
     """List length""" 
     return len(self._list) 

    def __getitem__(self, ii): 
     """Get a list item""" 
     return self._list[ii] 

    def __delitem__(self, ii): 
     """Delete an item""" 
     del self._list[ii] 

    def __setitem__(self, ii, val): 
     # optional: self._acl_check(val) 
     return self._list[ii] 
    def __str__(self): 
     return str(self._list) 
    def insert(self, ii, val): 
     # optional: self._acl_check(val) 
     self._list.insert(ii, val) 
    def append(self, val): 
     self.insert(len(self._list), val) 
+4

'self = []' no hace lo que crees que hace. –

+1

'super (HostList, self) .__ init __ (self)' haría el truco. Lo que hace su código es reasignar la variable (argumento) 'self' a' [] '. –

+0

'__getitem__' devolverá un objeto de lista si se especifica un sector. Puede cambiar el inicializador a '__init __ (self, l = None)' que usará una lista si se proporciona. Luego en '__getitem__', si ii es un objeto de corte, entonces devuelve' HostList (self._list [ii]) ' –

Respuesta

7

Si puede evitarlo, no herede las clases integradas. (Usted puede , pero eso no significa que usted debe sin una razón muy convincente)

Estas clases están optimizadas para la velocidad, y eso hace que hereda de forma correcta bastante tedioso, ya que acaban de tener que anular casi todo.

En realidad, heredar de collections.MutableSequence le permite implementar solo unos pocos métodos esenciales y obtener una implementación robusta con todas las funciones de la secuencia API, sin todas las peculiaridades y advertencias que vienen con la herencia de list.

+0

Gran punto +1 ... Después de algunas dificultades, lo tengo trabajando con 'collections.MutableSequence' ... ¡Gracias! –

6

Utilice isinstance para verificar sus objetos para ver si son instancias de Host, y use super (por ej. super(HostList, self).insert(...)) para usar la funcionalidad list, en lugar de volver a implementarla usted mismo.

Usted debe terminar con algo como:

def append(self, obj): 
    """append to the list...""" 
    if not isinstance(obj, Host): 
     raise RuntimeError, "Cannot append a '%s' object to a HostList" % obj.__class__.__name__ 
    super(HostList, self).append(obj) 
+1

Mejor aún, defina un método estático 'as_host (x)' que devuelva 'x' si es un host, de lo contrario arroja la excepción apropiada. Entonces las llamadas 'super' se convierten en frases únicas. –

0

Se podría llamar list 's método de su método, con super(). De esta forma, no es necesario arriesgarse con los otros métodos.

3

A menos que exista una razón convincente para que su contenedor HostList sea compatible con la interfaz del contenedor mutable, sugiero usar un modelo has-a en lugar de is-a. Tendrá la carga adicional de garantizar la coherencia del tipo con operaciones como cortar (devolver un contenedor HostList en lugar de una lista).

Cuestiones relacionadas