Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emulating the list.insert() method as a subclass of Python's list

I'm trying to build a class that inherits methods from Python's list, but also does some additional things on top... it's probably easier just to show code at this point...

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

My problem is this... if I want to perform the same kind of object admission tests on insert() as I did on append(), I can't find a way to code the new methods without to sacrificing support for one list expansion method (i.e. list.append(), list.insert(), or list.extend()). If I try to support them all, I wind up with recursive loops. What is the best way around this problem?

EDIT: I took the suggestion about subclassing collections.MutableSequence instead of Python's list()

The resulting code... posting here in case, it helps someone...

from collections.abc 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):
        # Good MutableSequence() implementation example in the cpython git repo:
        #    https://github.com/python/cpython/blob/208a7e957b812ad3b3733791845447677a704f3e/Lib/collections/__init__.py#L1215
        if isinstance(ii, slice):                                               
            return self.__class__(self._list[ii])                                
        else:                                                                   
            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)
like image 441
Mike Pennington Avatar asked Apr 07 '11 19:04

Mike Pennington


People also ask

Can you insert into a list Python?

You can use the insert() method to insert an item to a list at a specified index. Each item in a list has an index. The first item has an index of zero (0), the second has an index of one (1), and so on.

What is __ class __ in Python?

__class__ is an attribute on the object that refers to the class from which the object was created. a. __class__ # Output: <class 'int'> b. __class__ # Output: <class 'float'> After simple data types, let's now understand the type function and __class__ attribute with the help of a user-defined class, Human .

How do you create a list from a class in Python?

We can create a list of object in Python by appending class instances/object to list. By this, every index in the list can point to instance attributes and methods of the class and can access them.


1 Answers

If you can possibly avoid it, don't inherit from builtin classes. (You can, but that doesn't mean you should without a really compelling reason)

Those classes are optimised for speed, and that makes inheriting from them correctly quite tedious, since you end up having to override almost everything.

Inheriting from collections.MutableSequence instead lets you implement just a few essential methods, and get a robust fully featured implementation of the sequence API, without all the quirks and caveats that come with inheriting from list.

like image 112
ncoghlan Avatar answered Sep 21 '22 23:09

ncoghlan