Reputation: 1490
To explain my query I have a simple code snippet below followed by my question.
def count_vowels(s):
num_vowels = 0
for char in s:
if char in 'aeiouAEIOU':
num_vowels = num_vowels + 1
return num_vowels
print(count_vowels(""))
print("" in "aeiouAEIOU")
gives an output
0
True
My doubt:
Why does an empty string ""
returns True
for the expression
"" in "aeiouAEIOU"
But it skips when it is present along with a for loop?
for char in s:
My understanding is that empty strings are a subset of all strings then why it is ignored when the same expression is in the for loop? Feel free to correct me if there is something I am missing here.
Upvotes: 4
Views: 1913
Reputation: 16526
Your understanding is correct: "empty strings are a subset of all strings"
But now let's see what happens when we use for
for a sequence type such as string. Let's say we have:
lst = [1, 2, 3, 4, 5]
for i in lst:
print(i ** 2)
You can just think that it turns into:
index = 0
while True:
try:
i = lst.__getitem__(index)
except IndexError:
break
print(i ** 2)
index += 1
In your Example, when it tries to get even the first item, it will raise an Exception and break out of the loop. So it doesn't even go inside For
loop.
I said "just think" because in for-loop, iter()
is get called on the object (here lst
) and this built-in function will get an iterator out of the object. In order this to be happened the object should implement either the iterable protocol which is either __iter__
or it must support the sequence protocol (the __getitem__()
)).
lst = [1, 2, 3, 4, 5]
it = iter(lst)
while True:
try:
i = next(it)
except StopIteration:
break
else:
print(i ** 2)
Both str
and list
object have __iter__
so that is the method gets called rather than __getitem__
. (__iter__
has precedence over __getitem__
)
Upvotes: 4
Reputation: 27214
The expression "" in s
returns True
for all strings s
, because the empty string is trivially contained in all strings: the expression A in B
is akin to asking the question βis there a pair of indices i
and j
such that B[i:j] == A
β. If A
is the empty string, we can always just set both i
and j
to zero, so the answer is yes.
However, iterating over code points of the empty string does not yield ""
, it yields nothing at all. Observe:
def iterate(what):
print("iterating over {}".format(repr(what)))
for item in what:
print("item: {}".format(repr(item)))
print("iteration done")
print()
iterate("abc")
iterate("πͺπΊ")
iterate("")
The above code will print:
iterating over 'abc'
item: 'a'
item: 'b'
item: 'c'
iteration done
iterating over 'πͺπΊ'
item: 'πͺ'
item: 'πΊ'
iteration done
iterating over ''
iteration done
In your example, the loop body will never run, so it will never increment the vowel counter.
Upvotes: 0
Reputation: 114
In the second print command you're asking does ""
appear in "aeiouAEIOU"
and that is True
.
However, the length of ""
is 0. So the for loop doesn't execute even once since there are no items to iterate over.
Upvotes: 3