Instead of having those ifs you could use a translation table to speed things up (see str.maketrans and seestr.translate).
import string
def _build_translation_table():
ascii_vowels = 'aeiou'
d = {c: chr(ord(c)+1) for c in string.ascii_lowercase}
d['z'] = 'a' # z is a special case
for k, v in d.items(): # and so are vowels
if v in ascii_vowels:
d[k] = v.upper()
return str.maketrans(d)
_TABLE = _build_translation_table()
def LetterChanges(s):
"""Change letters in string s using a special algorithm.
Replace every letter in the string with the letter following it in the
alphabet (ie. c becomes d, z becomes a) ...
>>> LetterChanges('qwertyuiop')
'rxfsUzvjpq'
>>> LetterChanges('1234567890')
'1234567890'
>>> LetterChanges('zxcvbnm')
'AydwcOn'
"""
return s.translate(_TABLE)
if __name__ == '__main__':
import doctest
doctest.testmod()
I took the liberty to rename the parameter str to s for reasons already mentioned by others. _build_translation_table and _TABLE start with an underscore because it doesn't make much sense for them to be "public".
I also took some tests from Josay's answer and put them into the documentation string of the function, so that the doctest module can run them.
# python3 letterchanges.py -v
Trying:
LetterChanges('qwertyuiop')
Expecting:
'rxfsUzvjpq'
ok
Trying:
LetterChanges('1234567890')
Expecting:
'1234567890'
ok