Why does defining __getitem__ in a class make it iterable in python?

Why does defining __getitem__ in a class make it iterable?

For example, if I write:

class b: def __getitem__(self, k): return k cb = b() for k in cb: print k 

I get the output:

 0 1 2 3 4 5 6 7 8 ... 

I would really expect to see the error returned from "for k in cb:"

+42
python iterator overloading
May 29 '09 at 15:22
source share
6 answers

If you look at PEP234 defining iterators, it says:

 1. An object can be iterated over with "for" if it implements __iter__() or __getitem__(). 2. An object can function as an iterator if it implements next(). 
+38
May 29 '09 at
source share

Iteration support for __getitem__ can be thought of as an "obsolete function" that allows for a smoother transition when PEP234 introduces iterability as its primary concept. It applies only to classes without __iter__ , where __getitem__ takes integers 0, 1, and c and raises IndexError after the index gets too high (if ever), usually the "sequence" classes encoded before __iter__ , appeared (although nothing prevents you from coding new classes as well).

Personally, I would prefer not to rely on this in the new code, although it is not outdated and does not go away (works fine in Python 3 as well), so this is just a matter of style and taste ("explicit is better than implicit", so I would prefer explicitly maintain iterability, rather than relying on __getitem__ , supporting it implicitly for me, but not big).

+45
May 29, '09 at 15:37
source share

__getitem__ precedes the iterator protocol and was in the past the only way to make things iterable. Thus, it is still supported as an iteration method. Essentially, the protocol for iteration:

  • Check out the __iter__ method. If it exists, use the new iteration protocol.

  • Otherwise, try calling __getitem__ with successively large integer values ​​until it raises an IndexError.

(2) was the only way to do this, but had the disadvantage that it assumed more than was required to support only iteration. To support iteration, you had to maintain random access, which was much more expensive for things like files or network streams, where moving forward was easy, but going back would require storing everything. __iter__ allows iteration without random access, but since random access usually allows iteration anyway, and since backward compatibility violation will be bad, __getitem__ is still supported.

+18
May 29 '09 at 15:38
source share

Special methods such as __getitem__ add special types of behavior to objects, including iteration.

http://docs.python.org/reference/datamodel.html#object. getitem p>

"for loops, an IndexError is expected to be raised for illegal indices to ensure proper detection of the end of the sequence."

Raise an IndexError to signal the end of the sequence.

Your code is basically equivalent:

 i = 0 while True: try: yield object[i] i += 1 except IndexError: break 

Where the object is what you are repeating in a for loop.

+5
May 29 '09 at 3:28
source share

This is for historical reasons. Prior to Python 2.2, __getitem__ was the only way to create a class that could be repeated with a for loop. The __iter__ protocol was added in 2.2, but __getitem__ still works for loops to maintain backward compatibility.

+4
May 29 '09 at 15:38
source share

Because cb[0] same as cb.__getitem__(0) . See python documentation on this subject.

+3
May 29 '09 at 3:26
source share



All Articles