Se um objeto não tiver uma __contains__implementação,in retornará a um padrão que basicamente funciona assim:
def default__contains__(self, element):
for thing in self:
if thing == element:
return True
return False
E se um objeto não tiver uma __iter__implementação,for retornará a um padrão que basicamente funciona assim:
def default__iter__(self):
i = 0
try:
while True:
yield self[i]
i += 1
except IndexError:
pass
Esses padrões são usados mesmo que o objeto não seja uma sequência.
Seus testes 1 in fe 5 in festão usando os fallbacks padrão para ine for, levando ao comportamento observado. 1 in fencontra 1imediatamente, mas seu __getitem__nunca retorna 5, então5 in f corre para sempre.
(Bem, na implementação de referência do Python, o __iter__fallback padrão armazena o índice em uma variável do tipo C-level Py_ssize_t, portanto, se você esperar o suficiente, essa variável atinge o limite máximo e o Python gera um OverflowError . Se você viu isso, deve estar em uma versão Python de 32 bits. Os computadores não existem o suficiente para que alguém possa acessá-la em um Python de 64 bits.)