I guess the author of the slide didn't actually test the code.
The code you produced is trying to use map()
to call s
as a function:
map(s,s[3:]+ s[:3])
# ^ This must be a *callable object*, like a function
If you wanted to create a dictionary mapping ASCII letters to a letter 3 spots along in the alphabet, use the zip()
function instead:
d = dict(zip(s, s[3:] + s[:3]))
zip()
then pairs up each element in s
with each element in s[3:] + s[:3]
, and those (letter, letter + 3)
pairs are then passed to dict()
to form key-value pairs:
>>> s = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
>>> dict(zip(s, s[3:] + s[:3]))
{'A': 'D', 'I': 'L', 'L': 'O', 'X': 'A', 'N': 'Q', 'D': 'G', 'S': 'V', 'B': 'E', 'V': 'Y', 'C': 'F', 'K': 'N', 'W': 'Z', 'R': 'U', 'O': 'R', 'T': 'W', 'P': 'S', 'F': 'I', 'J': 'M', 'M': 'P', 'E': 'H', 'Q': 'T', 'H': 'K', 'G': 'J', 'Z': 'C', 'U': 'X', 'Y': 'B'}
Next, your last line will completely fail to do any encryption, because your map only handles uppercase letters, but you lowercased your input. Either produce a lowercase map, or lowercase your input.
Lowercasing the map could look like this:
def encrypt_caesar(plaintext):
s = "abcdefghijklmnopqrstuvwxyz"
d = dict(zip(s, s[3:] + s[:3]))
return ''.join(map(lambda l: d.get(l, l), plaintext.lower()))
or you could just use the string.ascii_lowercase
constant:
from string import ascii_lowercase
def encrypt_caesar(plaintext):
d = dict(zip(ascii_lowercase, ascii_lowercase[3:] + ascii_lowercase[:3]))
return ''.join(map(lambda l: d.get(l,l), plaintext.lower()))
Using this method is rather slow, however. For blazingly-fast 'encryption', use the str.translate()
method; the input map for that is best produced with str.maketrans
:
from string import ascii_lowercase as alc
def encrypt_caesar(plaintext, shift=3):
map = str.maketrans(alc, alc[shift:] + alc[:shift])
return plaintext.lower().translate(map)
I added a shift
parameter to define how much of an alphabet shift should be applied.
I'll leave handling both lowercase and uppercase letters as an exercise to the reader!