ProgrammingBackend Developer

How is the sequence interface (Sequence) implemented in Python? Why is it necessary to implement special methods __getitem__, __len__, and what pitfalls exist?

Pass interviews with Hintsage AI assistant

Answer.

Background:

Sequences are one of the oldest and most fundamental concepts in Python. Classic examples include lists (list), strings (str), and tuples (tuple). A special protocol has been defined for interacting with sequences: you need to implement the __getitem__ and __len__ methods. This allows an object to behave "like a sequence"—supporting indexing, slicing, loop operations, and even certain standard functions.

Problem:

Without proper implementation of these methods, a user-defined class will not work with indexing operations, for-loops, or functions like len(). Often, beginner developers implement only one of the methods, neglect exception handling, and do not support slicing, leading to incorrect or unexpected behavior.

Solution:

You need to implement the __getitem__(self, key) method to support indexing and slicing, as well as __len__(self) for working with the len() function and proper iterability. To support slicing, you must differentiate the type of key in __getitem__ and correctly handle slice objects.

Code Example:

def is_even(n): return n % 2 == 0 class EvenSequence: def __init__(self, size): self.size = size def __getitem__(self, index): if isinstance(index, slice): return [x for x in range(self.size)[index] if is_even(x)] if index < 0 or index >= self.size: raise IndexError('Index out of bounds') return index if is_even(index) else None def __len__(self): return self.size

Key Features:

  • Interacts with most functions and syntax in Python if both methods are implemented.
  • To support slicing, slice-type objects must be handled in getitem.
  • Failure to implement len will prevent the object from working with len() and some standard functions.

Trick Questions.

Can we rely solely on the getitem method for the object to work as a sequence?

Partially. If only __getitem__ is implemented, the object can be iterated over via for and indexed, but len() will not work.

Code Example:

class SeqOnlyGetitem: def __getitem__(self, index): if index >= 10: raise IndexError return index * 2 s = SeqOnlyGetitem() for x in s: print(x) # Works (iterable) # print(len(s)) # This raises TypeError

How to handle negative indices and what happens if they're not considered?

Negative indices are a key feature of sequences in Python. If they're not handled, the object behaves unexpectedly for the user.

class NegIndex: def __init__(self, data): self.data = data def __getitem__(self, index): if index < 0: index += len(self.data) return self.data[index]

Is it necessary to implement contains or iter for your Sequence class?

Not necessarily. If __getitem__ and __len__ are implemented, the in operator will work, and for will use them for iteration. Implementing these methods directly is usually not required, but can improve performance.

Common Mistakes and Anti-patterns

  • Failing to check index ranges, leading to IndexError or unexpected results.
  • Not implementing support for slicing (slice), so obj[2:10:2] raises an error.
  • Forgetting about negative indices (obj[-1]).

Real-life Example

Negative Case

A developer implemented only getitem for their class for positive indices only. The module passed part of the unit tests, but in real use, attempts to access non-existing or negative indices broke everything.

Pros:

  • Quick initial implementation.

Cons:

  • Unexpected errors in practice.
  • Inconvenience during use (unable to access last elements via negative index, slicing does not work, len() does not work).

Positive Case

The team implemented both methods (getitem and len), considered slicing, negative indices, and raised correct exceptions. The final class worked in all standard Python cases.

Pros:

  • Predictable behavior from Python's API perspective.
  • User-friendly, minimal bugs.

Cons:

  • Slightly more code, requires attention to detail during design.