Hmmm...even I am bamboozled! I think since example="" , it takes example to be null string and checks it in "Hello There" and returns True, but this doesn't:

>>> example=""
>>> "Hello There" in example
False
>>>

When you're working with strings, s in t means that s is a substring of t. The question is what is a substring ? We could give 2 defintitions, first s is a substring of t if there are strings x and y such that t == x + s + y. When s is empty, this is always true, because you can write t == "" + "" + t. Another possible definition is that s is a substring of t if s == t[a:b] for 2 numbers a and b. Again, one has "" == t[0:0]. So it'scoherent to define the empty string as a substring of any string. In the same way, mathematicians define the empty set as a subset of any set. In python: set().issubset(set("hello")) ---> True .

It would explain a massive bug i had in my code a year or two ago :P
So basically is there any easy way you would get around it so that example in "Hello there" gives False?

You could use (bool(example) and example in "hello there") . This is true only if example is a non empty substring of "hello there".

There is no need to convert the example string to bool before testing.
All objects in Python have a True/False value.

if example and (example in "hello there"):
pass

I placed the () around the in test because there is no confusion about the operator precedence of and and in .

The result of a boolean test (and/or) is not True or False, it is the value of the object that gives the outcome of the test. We use lazy evaluation, stop analyzing the expression when the answer is already known. For 'and' one item is False, for 'or' one item is True

>>> str1 = ''
>>> str2 = 'Hello'
>>> str1 and str2 # at str1 the outcome is known
''
>>> str2 and str1 # at str1 the outcome is known
''
>>> str3 = 'World'
>>> str2 and str3
'World'
>>> str1 or str2
'Hello'
>>> str2 or str3
'Hello'
>>> obj1 = 1234
>>> str2 and obj1 # not only for equal type of objects
1234

There is no need to convert the example string to bool before testing.
All objects in Python have a True/False value.

I put the bool intentionally, I wanted an expression with a boolean value. In principle, you're right, I often write if s: ... if L: ..., if D: ... when working with strings, lists and dicts. However, I think that when the expression is too complicated, it's better to write an expression which obviously returns a boolean value. A good reason to do that is that if I read the code 6 month later, I see immediatly what the expression does. Without the bool, I need some time to realize that the value of the expression could very well be "hello". Such hidden features are bad if I decide to modify the program. If I don't cast explicitely to bool, the interpreter will do it anyway when it executes the 'if' statement.