Slower? Maybe. In a way that matters? Not in the slightest, it’s still a constant amount of time spent on each character.
For example if you have a phone book and want to count how many times “John” is in it, it would be fast to read through the phone book once and add 1 to some variable each time “John” is encountered, but it would be slow to start over each time a new “John” is encountered. Whether the last name is checked as well is insignificant, it’s not worth considering.
My guess would actually be that it’s faster because generators come with some overhead. List comprehension might be faster. But that’s guessing, and either way it’s insignificant so I won’t bother figuring out which is the case.
In any case, the reason for writing a regular loop is only for figuring out what goes where. They have the same parts - a place where something’s done, a place to specify an iterable, a place for creating variables.
If I wanted to add 3 to each number in some list, I would do that in the body of the for-loop, wouldn’t I? Converting to lowercase is a similar action, it would go in the same place.
What if you tried to write a function like this?:
def add(c = a + b):
Is that valid python? For all you know this might be some fancy feature, it might be valid. But you’d probably think that it should look like this instead:
def add(a, b):
return a + b
Because the function body is where actions are meant to be carried out, not in the argument list.
(and it is valid, but does something else because the different parts in the function statement are treated differently or otherwise there may as well only be one part to it)
results = 
for c = a + b in numbers:
Not quite huh.
Same thing with list comprehension. Look at what the different parts do and put code where you need it to be. Lots of examples to be found by searching, and you can modify those examples to see how they affect the outcome.