Playing around, I found that the generator approach was competitive with this if you permuted the loop nest, and often even slightly faster (at the 1000 character length):
def any_gen_perm(s):
return any(c in s for c in "aeiouAEIOU")
I think the crux is that you want the inner loop inside the fast C-implemented primitive to be the one iterating over the longer string, and to leave the outer loop in Python to iterate over the shorter string. With both my version and yours, the Python loop only iterates and calls into the C search loop 10 times, so there's less interpreter overhead.I suspect that permuting the loop nest in similar variations will also see a good speed up, and indeed trying just now:
def loop_in_perm(s):
for c in "aeiouAEIOU":
if c in s:
return True
return False
seems to give the fastest result yet. (Around twice as fast as the permuted generator expression and your find implementation on my machine, with 100 and 1000 character strings.)