How can I make this Python code more efficient

Kieran

I would greatly appreciate your feedback on my first ever Python project! :D

Basically I am coding a Caesar Cipher and I think its pretty terribly 'optimised / efficient' if you know what I mean, this is because I copied and pasted the encrypt() method for the decrypt() method and the only thing I changes was instead of rotating the numbers more, I rotated them less. This is what I'm talking about:

       newPosition = (abc.find(letter) - key) % 26

^^ Instead of having a + (plus) I made it a - (minus) ^^

Is there a way I can sort of call the encrypt() method at just the newPosition line? Or what I did was correct and it doesn't need fixing (which I highly doubt)

** Please do take in mind that I do not have much knowledge in Python (if any at all) since I just started today so don't blow my brain up with some super complex code. THANK YOU!!! **

abc = 'abcdefghijklmnopqrstuvwxyz'

def main():
    message = input("Would you like to encrypt or decrypt a word?")
    if message.lower() == "encrypt":
        encrypt()
    elif message.lower() == "decrypt":
        decrypt()
    else:
        print("You must enter either 'encrypt' or 'decrypt'.")
        main()


def encrypt():
    message = input("Enter a message to encrypt: ")
    message = message.lower()
    key = int(input("What number would you like for your key value?"))
    cipherText = ""
    for letter in message:
        if letter in abc:
            newPosition = (abc.find(letter) + key) % 26
            cipherText += abc[newPosition]
        else:
            cipherText += letter
    print(cipherText)
    return cipherText

def decrypt():
    message = input("Enter a message to decrypt: ")
    message = message.lower()
    key = int(input("What number would you like for your key value?"))
    cipherText = ""
    for letter in message:
        if letter in abc:
            newPosition = (abc.find(letter) - key) % 26
            cipherText += abc[newPosition]
        else:
            cipherText += letter
    print(cipherText)
    return cipherText

main()
Adam Smith

In general, str.find is bad performance-wise. It's O(n) complexity, which isn't awful, but you rarely actually need it. In this case you can use ord to convert each letter to its ordinal, then subtract ord('a') to get 0-25 instead of 97-122.

This is particularly useful, because you can then use chr to convert back without needing a lookup.

for letter in message:
    if letter in string.ascii_lowercase:  # same as "abcdef..z"
        new_position = ((ord(letter) - ord('a') + key) % 26) + ord('a')
        new_ch = chr(new_position)
        ciphertext += new_ch

Note also that concatenating strings with += isn't as fast as something like str.join.

new_letters = [chr(((ord(letter) - ord('a') + key) % 26) + ord('a')) if letter in ascii_lowercase else letter for letter in message]
ciphertext = "".join(new_letters)

And since that chr(((ord(letter) - ord('a') + key) % 26) + ord('a')) is so ugly, I'd refactor that into a function.

def rotate(letter, key=0):
    c_pos = ord(letter) - ord('a')
    rotated = c_pos + key
    modded = rotated % 26
    final_pos = modded + ord('a')
    return chr(final_pos)

new_letters = [rotate(c, key) if c in string.ascii_lowercase else c for c in letters]
ciphertext = "".join(new_letters)

A point of maintainability: it's easier to write testably good code if you separate your inputs from your results. Right now you'd have to do some monkey patching of stdin to write unit tests for any of your functions, but if you move your requests for user input into main and out of their respective function, that gets much easier.

def main():
    message = input("What's the message to encrypt/decrypt? ")
    key = int(input("What number would you like for your key value? "))
    choice = input("Choose: encrypt or decrypt. ")
    if choice == "encrypt":
        result = encrypt(message, key)
    elif choice == "decrypt":
        result = decrypt(message, key)
    else:
        # something here about a bad user input.

In fact, when you consider the Caesar Cipher is reversible by flipping the sign of the key, you can simply do:

    if choice == "encrypt":
        result = encrypt(message, key)
    elif choice == "decrypt":
        result = encrypt(message, key * (-1))

and not write a decrypt function at all!

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

How can I make this python code more efficient?

How can I make a code more efficient and shorter?

How can I make this C# code more efficient?

How can I make my pandas code more efficient?

How can I refactor this code snippet to make it more efficient?

How can I use iteration to make this vbnet code more efficient?

How can I concatenate my code properly and make this more efficient?

How can I optimize this VBA code to make it more efficient and faster?

Why is this Python code so slow? How can I make it more efficient?

How can i make this script more efficient?(Python)

How can I make this loop more efficient?

How can I make this more efficient in Android?

How can I write this code more efficient?

How would I make this more efficient? (python)

Can I use classes or lists to make my code more efficient?

Can I make this Clojure code (scoring a graph bisection) more efficient?

How can I make my code more efficient in R - It's to repetitive

android - SQL database, how can I make my code more efficient

How can I make this PyTorch tensor (B, C, H, W) tiling & blending code simpler and more efficient?

I made a basic python calculator, how can I make it more efficient

How do I make this matching list code more efficient?

How would I make this code more compact/efficient?

Any idea how I could make this code more efficient?

Python: How can I make my implementation of bubble sort more time efficient?

How can I make my trie more efficient?

How can I make this PyTorch heatmap function faster and more efficient?

How can I make this search query more efficient?

How can I make a recursive search for longest node more efficient?

How can I make this more efficient path finding?