The Caesar cipher is also good, but I'd like to mention a couple of things.
The string module has constants for ascii_letters, ascii_uppercase, and ascii_lowercase.
A constant can be safely created outside of a function and still be used within it.
This is preferred when calculation is involved in creating the constant because it will only occur once instead of each time the function is called.
We should generally use str.join for string concatenation. In certain situations adding strings is faster than str.join, but in other situations adding strings occurs in quadratic time. O(n**2)
It's also possible to use a bytes translation to perform a Caesar shift, but you have to create the translation table for each shift. I think it would be less efficient than Lardmeister's implementation. However, if your program only ever needs shifts by one value, say 5, it might be better.