How to implement a minimal class that behaves like a sequence in Python?
Adding to @Jeremy's answer: A popular check that a value is a general sequence is to use isinstance(value, collections.Sequence)
.
In order to make this true for your type it needs to inherit from collections.Sequence
, and this actually provides the iterator (and some other useful functions) as mixins, as long as you provide the __len__
and __getitem__
functions.
Borrowing from @Jeremy's answer, an example class would look like:
import collections
class MySequence(collections.Sequence):
def __len__(self):
return 3
def __getitem__(self, key):
if key == 0:
return 1
elif key == 1:
return 2
elif key == 2:
return 3
else:
raise IndexError()
Examples of usage:
s = MySequence()
for i in range(len(s)):
print s[i] # prints 1, then 2, then 3
for x in s:
print x # prints 1, then 2, then 3
print isinstance(s, collections.Sequence) # prints True
print 1 in s # prints True
print list(reversed(s)) # prints [3, 2, 1]
If you just want to be able to iterate over your sequence, you just need to implement the __iter__
method returning an iterable. The easiest way to do this is to create a generator using the yield
statement.
class MySequence(object):
def __iter__(self):
yield 1
yield 2
yield 3
for x in MySequence():
print x # prints 1, then 2, then 3
However, this will not enable things like MySequence()[1]
. For that you need to implement the __getitem__
method, and should probably implement __len__
as well.
class MySequence(object):
def __len__(self):
return 3
def __getitem__(self, key):
if key == 0:
return 1
elif key == 1:
return 2
elif key == 2:
return 3
else:
raise IndexError()
s = new MySequence()
for i in range(len(s)):
print s[i] # prints 1, then 2, then 3
for x in s:
print x # prints 1, then 2, then 3
Notice that I omitted __iter__
. As long as __getitem__
raises an IndexError
when you try to get a value that's out-of-bounds, Python can use it for iteration. (I could still include __iter__
if I wanted to be clearer, or wanted non-standard iteration behaviour.)