2011-04-07 2 views
6

Я пытаюсь создать класс, который наследует методы из списка Python, но также делает некоторые дополнительные вещи сверху ..., вероятно, проще просто показать код на данный момент ...Эмуляция метода list.insert() в качестве подкласса списка 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 

Моя проблема ... если я хочу, чтобы выполнить тот же самый вид объекта вступительных испытаний на insert(), как я сделал на append(), я не могу найти способ для кодирования новые методы, не жертвуя поддержкой одного метода расширения списка (т.е. list.append(), list.insert(), или list.extend()). Если я попытаюсь поддержать их всех, я завершаю рекурсивными циклами. Каков наилучший способ решения этой проблемы?

EDIT: Я принял предложение о подклассов collections.MutableSequence вместо списка в Python()

Результирующий код ... размещения здесь в случае, это помогает кто-то ...

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 = []' не делает то, что вы думаете. –

+1

'super (HostList, self) .__ init __ (self)' будет делать трюк. Что делает ваш код, переназначить переменную (аргумент) 'self' на' [] '. –

+0

'__getitem__' вернет объект списка, если указан срез. Вы можете изменить инициализатор на '__init __ (self, l = None)', который будет использовать список, если он предоставлен. Затем в '__getitem__', если ii - объект среза, тогда возвращаем' HostList (self._list [ii]) ' –

ответ

7

Если вы можете избежать этого, не наследуйте от встроенных классов. (Вы можете , но это не означает, что вы РЕКОМЕНДУЕМЫМ без действительно веских причин)

Эти классы оптимизированы для скорости, и что делает унаследовав от них правильно довольно утомительно, так как вы в конечном итоге переопределить почти все.

Унаследованный от collections.MutableSequence вместо этого позволяет реализовать только несколько основных методов и получить надежную полнофункциональную реализацию API последовательности без всех причуд и оговорок, которые наследуются от list.

+0

Отличный момент +1 ... После некоторых битв я получил его с помощью 'collections.MutableSequence' ... Спасибо! –

6

Используйте isinstance, чтобы проверить, являются ли они экземплярами Host, и используйте super (например, super(HostList, self).insert(...)), чтобы использовать функциональность list, а не переопределять его самостоятельно.

Вы должны закончить с чем-то вроде:

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

Еще лучше определить статический метод 'as_host (x)', который возвращает 'x', если это хост, иначе выбрасывает соответствующее исключение. Затем вызовы 'super' становятся однострочными. –

0

Вы могли бы назвать list «s метод из метода, с super(). Таким образом, вам не нужно смешивать его с другими методами.

3

Если у вас есть веская причина, что контейнер HostList полностью поддерживает измененный интерфейс контейнера, я предлагаю использовать модель has-a rather than is-a. У вас будет дополнительное бремя обеспечения согласованности типов с такими операциями, как нарезка (верните контейнер HostList, а не список).