I understand that Python's `in` operator can check for substrings in strings—for example, `"hell" in "hello world"` returns `True`. I expected similar behavior for other sequence types, such as `(1, 2, 3) in (4, 1, 2, 3, 5)`, but that expression returns `False`. Why doesn't tuple or list membership work like string substring matching, and what is the right way to check for consecutive elements or simply confirm that all elements are present?
3 Answers
If you only need to know whether all requested values occur somewhere in an iterable, use sets when the values are hashable: `set((1, 2, 3)).issubset((4, 1, 2, 3, 5))`. If order and adjacency matter, you need a subsequence check, such as comparing each sliding window of three elements with `(1, 2, 3)`.
Strings have special substring behavior, but extending that automatically to every container would be ambiguous, especially with nested values. For example, `(2, 3)` could mean a consecutive subsequence in `(1, 2, 3, 4)`, or it could mean one exact element in `((1, 2), (2, 3), (3, 4))`. Python keeps `in` as direct element membership for tuples, lists, and similar containers.
For tuples and lists, `in` checks whether the left-hand object is one complete element of the container. So `(1, 2, 3) in (4, 1, 2, 3, 5)` asks whether the outer tuple contains a tuple element equal to `(1, 2, 3)`. It does not search for a consecutive subsequence. This does return `True`: `(1, 2, 3) in ((1, 2, 3), 4, 5)`.

That distinction is important: set comparison ignores order and duplicates, while a sliding-window approach preserves both sequence order and adjacency.