The official documentation indicates that python first tries to check via __contains__()
, then __iter__()
, and finally __getitem__()
, depending on which function is defined, in order to resolve an in
call.
Eg:
if y in x:
print("y present in x")
else:
print("y not present in x")
The linked documentation indicates that if there exists any non negative index i
such that x[i] == y
, then the result is True
else False
.
How does it perform a search over all such i
? A linear traversal over 'all' positive numbers seems out of the question. There must be some bounds in which the linear traversal happens (for lists, it should be 0 to len()). How are those bounds determined?
Aaah, I think get it... You want to know how the key is obtained to iterate over all elements on custom containers that do not have neither __contains__()
nor __iter__()
- simple, it works exactly using linear iteration until IndexError
is encountered, as stated in the documentation:
... if a class defines
__getitem__()
,x in y
isTrue
if and only if there is a non-negative integer indexi
such thatx == y[i]
, and all lower integer indices do not raiseIndexError
exception. (If any other exception is raised, it is as if in raised that exception).
Case in point:
class CustomClass(object):
def __getitem__(self, item):
if item > 20: # lets force the break so that it doesn't go to sys.maxsize
raise IndexError()
print(item) # print the item requested
# implied: return None so it doesn't match 5
result = 5 in CustomClass() # this will keep printing numbers until 20