While we're talking about weird Python edge cases, what do you think this does?
```
class Foo:
def __getitem__(self, i):
return i
def __len__(self):
return 5
print(list(Foo()))
```
While we're talking about weird Python edge cases, what do you think this does?
```
class Foo:
def __getitem__(self, i):
return i
def __len__(self):
return 5
print(list(Foo()))
```
The answer is so counter-intuitive to me that I have independently discovered it twice, about a year apart, and posted outraged comments about it in discord both times, and the second time had to be reminded that this was not the first time I'd discovered the behaviour.
It's possible it's also not the first time I've posted it on mastodon.
@cfbolz Correct, yes. It will hang until it eventually runs out of memory.
Now, do you know why?
@DRMacIver @cfbolz Wild guess: the iteration doesn't consult `__len__`, but just keeps retrieving incremental indexes waiting for one to raise an exception.
UPDATE: my language is sloppy, but you get what I'm arm-waving about.
@cfbolz @tartley Yup, exactly that. Default iteration is like:
```
i = 0
while True:
try:
yield x[i]
except IndexError:
break
i += 1
```
Instead of:
```
for i in range(len(x)):
yield x[i]
```
In some sense you should never be able to tell the difference in correct code, so you'll rarely notice this, but I've at least twice managed to write incorrect code that doesn't raise for out of bounds access
@ossmkitty @tartley @dabeaz @DRMacIver yeah, exactly, thank! I was just hunting that down too! basically it's because index.__get__ does not exist.
so this works for anything that's callable with one argument but without __get__. things I just tried:
@cfbolz @ossmkitty @tartley @dabeaz @DRMacIver Ohoho, those look just like the kind of weirdness that can uncover interpreter and extension bugs!
Thank you for your contribution to my fuzzing habit :)
This PEP proposes adding an nb_index slot in PyNumberMethods and an __index__ special method so that arbitrary objects can be used whenever integers are explicitly needed in Python, such as in slice syntax (from which the slot gets its name).
@dabeaz @tartley @DRMacIver heh, that's a slightly mean exercise.
My main question is why we still use named tuples at all, now that data classes are a thing
@tonyg TBF these are not exactly contradictory. This isn't the normal iterator protocol, it's the fallback protocol for C-style iteration when you don't have an iterator.
Still hate it though.
@DRMacIver Seems reasonable - just this fallback thing that's, er, underdocumented is less than reasonable...
This, for example, produces 0 thru 4 when iterated over, and checking the pep and a few cursory google searches did not explain this satisfactorily:
class Foo:
def __getitem__(self, i):
if i < 5: return i
raise IndexError()