In Python, the membership operator can search for substrings in strings, so `"hell" in "hello world"` evaluates to `True`. I expected similar behavior for sequences, such as `(1, 2, 3) in (4, 1, 2, 3, 5)`, but that expression returns `False`. Why doesn't Python treat the smaller tuple as a consecutive sequence inside the larger one, and what is the right way to perform that kind of check?
4 Answers
If you need to check whether all the values occur somewhere in a larger iterable, convert both collections to sets and use `issubset()`, assuming the values are hashable: `set((1, 2, 3)).issubset((4, 1, 2, 3, 5))`. This ignores order and duplicates, so it is not the same as checking for a consecutive sequence.
For tuples and lists, `in` checks whether the left-hand object is one complete element of the container. In `(4, 1, 2, 3, 5)`, the elements are individual integers, so the tuple `(1, 2, 3)` is not present as a single element. This is different from strings, where substring searching is specifically part of the string membership behavior.
Automatically treating a tuple as a subsequence would be ambiguous, especially with nested containers. For example, `(2, 3)` could mean consecutive values inside `(1, 2, 3, 4)`, or it could mean an exact element inside `((1, 2), (2, 3), (3, 4))`. Python keeps normal container membership as an element-level operation.
For a consecutive subsequence, use a sliding-window check. One simple approach is `any(values[i:i+len(target)] == target for i in range(len(values) - len(target) + 1))`, where `values` is the larger sequence and `target` is the sequence being searched for. This preserves order and requires the items to be adjacent.

That’s why `(1, 2, 3) in ((1, 2, 3), 4, 5)` is `True`: the tuple appears there as one nested element. It is not checking across neighboring elements.