Point of note: collections.Counter() behaves as if every possible element is in it, yet it isn’t infinitely iterable. This isn’t a problem, since it has a different definition of iterability, but it goes to show that synthesizing results in response to __getitem__ doesn’t mean they have to be iterated over.
Steve, I know how you adore a good argument, but just because you can catch the OP on a few technicalities (like talking about an implicit __iter__ function, when really what’s under discussion is iterability in general - yes, congratulations, you found a technical error), don’t assume that the argument’s merits do not exist. It IS surprising that some forms of __getitem__ will make an object iterable and others will not. For instance, this one will not:
>>> class X:
... def __getitem__(self, item):
... if isinstance(item, float): return item
... raise KeyError
...
But this one will:
>>> class X:
... def __getitem__(self, item):
... if isinstance(item, int): return item
... raise KeyError
...
Yes, it’s documented. It doesn’t mean it won’t be surprising.
(And yes. Programmers most certainly ARE users, and the Principle of Least Astonishment absolutely DOES apply. I have had the unpleasant experience of working with a number of highly surprising APIs, and it is not something to wish on one’s worst enemy.)
(Unless your worst enemy is a self-aggrandized Wordpress “expert” who charges exorbitant rates for minimal work, in which case (a) they deserve everything that PHP can throw at them, and (b) you deserve a better enemy.)