Q:

Can `in` operator in Python be used other than checking for membership in a sequence?

in operator in Python is a membership operator that tests for membership in a sequence. 
Description of in operator

Evaluates to true if it finds a variable in the specified sequence and false otherwise.

Now consider the code:
>>>s = 'HELLO'
>>>char = 'M'
>>>char in s
False
>>>for char in s:
....    print(char)
H
E
L
L
O

Please correct me here:
I think the statement for char in s should check for 'M' in 'HELLO' which should be evaluated to False and the loop should be terminated. But here, instead of checking for the membership, it is assigning every character to the variable char and thus the loop is printing the every character.
My question is, how in operator can be used other than checking the membership?

A:

The in keyword is used in two different contexts:

Membership test
Iteration

The first, as you said, checks if something belongs to a sequence, by calling that sequence's __contains__. When using this syntax, a boolean value is returned.
x = 1
l = [0, 1, 2]
if x in l:
    print("x is in l")
else:
    print("x is not in l")

> x is in l
Since in looks for the __contains__ method, x in seq is valid as long as seq implements a __contains__ method. You can implement this, even though it does not make logical sense, regarding the concept of membership.
class Foo:
    def __contains__(self, x):
        return x == 12

f = Foo()
if 12 in f:
    print("12 is in f")
> 12 is in f

The second is actually more often used. According to an iteration protocol, it enumerates the elements of an iterable object, so that actions can be performed on them.
You can iterate over a list:
l = [0, 1, 2]
for x in l:
    print(x)
> 0
> 1
> 2
Over a string:
s = "hello"
for c in s:
    print(c)
> h
> e
> l
> l
> o
And over any object implementing the __iter__ method, as long as the latter returns an object that implements the __next__ method.
The following example is a basic (not to say "poor") range-like class, whose you can iterate over the instances.
class Bar:
    def __init__(self, first, last):
        self.first = first
        self.last = last
        self.current = first

    def __iter__(self):
        return self

    def __next__(self):
        if self.current == self.last:
            raise StopIteration
        result = self.current
        self.current += 1
        return result

b = Bar(0, 5)
for i in b:
    print(i)
> 0
> 1
> 2
> 3
> 4
A lot of native types are iterable: dictionaries, ranges, sets...

Semantically speaking, it makes sense to use the same in word for both contexts. "Is this thing in that stuff?" is a valid question, as long as "stuff" is a collection, which is capable of containing things. Henceforth, "do this for every thing in that stuff" seems pretty natural.
Hence the use of "in" for both contexts.
This is however quite a simplification of the reality, which is actually more vast. I invite you to read the documentation, and for an in-depth understanding of the in keyword, read Python's grammar.

