Lee
Lee

Reputation: 524

How to make an iterable class in Python in which only a specific type is allowed to be the element?

I want some Python class having similar methods as list (assuming it's called mylist) except that mylist accepts elements of a specific type (instances of another customed class to store some data in my case).

I read some posts on SO and knew that I need to override some methods as append, extend, insert. But I'm not sure about everything I need to override to guarantee that in all operations (e.g. append, add, extend, insert, slice...) to instances of mylist there will be no problem.

And if there is one more convenient way without needs to override so many methods?

Upvotes: 0

Views: 528

Answers (1)

mgilson
mgilson

Reputation: 310217

Sometimes, things are easier without inheriting from builtin objects...:

from collections import MutableSequence, Iterable

class MyList(MutableSequence):
    def __init__(self, type, iterable=()):
        self._data = []
        self._type = type
        self.extend(iterable)

    def insert(self, index, item):
        if not isinstance(item, self._type):
            raise TypeError
        self._data.insert(index, item)

    def __len__(self):
        return len(self._data)

    def __getitem__(self, *args):
        return self._data.__getitem__(*args)

    def __delitem__(self, *args):
        self._data.__delitem__(*args)

    def __setitem__(self, key, value):
         if isinstance(value, collections.Iterable) and isinstance(key, slice):
             values = []
             for val in value:
                 if not isinstance(value, self._type):
                     raise TypeError
         else:
             if not isinstance(value, self._type):
                 raise TypeError
         self._data[k] = value

Note, I haven't gone into any discussion about whether this is a good idea. Some people will tell you not to do this because python is built on "duck-typing". Others say that isinstance is perfectly fine to use -- provided that you do so responsibly. One proponent of this view (Alex Martelli) is generally regarded as a python expert. He recommends isinstance checking against abstract base classes and calls this practice "goose-typing". This practice seems to have gained some traction as the standard library is slowly adding support that would allow more robust run-time checking of these things -- Consider PEP-0484 (type hinting).

I suppose, my point is that if you use this class, don't do:

lst1 = MyList(list)
lst2 = MyList(int)

Do something like:

lst1 = MyList(collections.MutableSequence)
lst2 = MyList(numbers.Integral)

Upvotes: 4

Related Questions