Эмуляция метода list.insert () как подкласса списка Python - PullRequest
6 голосов
/ 07 апреля 2011

Я пытаюсь создать класс, который наследует методы из списка 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()).Если я попытаюсь поддержать их всех, я получу рекурсивные циклы.Как лучше обойти эту проблему?

РЕДАКТИРОВАТЬ: я принял предложение о создании подклассов коллекций.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 ]

7 голосов
/ 08 апреля 2011

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

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

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

6 голосов
/ 07 апреля 2011

Используйте 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)
3 голосов
/ 07 апреля 2011

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

0 голосов
/ 07 апреля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...