编写单字母Vigenère加密函数时遇TypeError错误,请求协助解决
Let's break down what's going wrong here and get your single-letter Vigenère encryption function working properly.
The TypeError: unsupported operand type(s) for %: 'list' and 'int' error pops up because your letnum variable is a list (even if it only has one value inside), and you're trying to use it in a modulus operation (%) with an integer—something Python doesn't allow.
Looking at your code:
letnum = [k for k, v in alphanumero.items() if v == inputlet[0]]
This list comprehension returns a list of matching keys, not a single integer. For example, if you input "A", letnum becomes [0]—a list, not the integer 0 you need for encryption math.
On top of that, your code has a couple of other early issues:
- Your
alphanumerodictionary uses numbers as keys and letters as values, but you first try to accessalphanumero[inputlet]using the input letter as a key. That's guaranteed to trigger aKeyErrorright away, since the dictionary has no letter keys. - You're only checking the first character of
inputlet, and not handling lowercase inputs (which won't match the uppercase letters in your dictionary).
Let's fix these issues and build out the full single-letter Vigenère cipher:
Step 1: Fix Letter-to-Number Conversion
Instead of returning a list, get a single integer. You can use next() to grab the first matching key (cleaner) or take the first element of the list (just make sure the input is valid):
# Convert input to uppercase first to handle lowercase inputs inputlet_upper = inputlet.upper() # Use next() to get the matching key (raises StopIteration if no match) letnum = next(k for k, v in alphanumero.items() if v == inputlet_upper) # Alternative: Grab the first element of the list (works if input is valid) # letnum = [k for k, v in alphanumero.items() if v == inputlet_upper][0]
Step 2: Add Vigenère Shift Logic
Vigenère needs a key (a single letter here). Convert that key to a number too, then calculate the shifted value using modulus 26 to stay within the alphabet range:
# Get and process the key letter keylet_upper = input("Enter key letter: ").upper() keynum = next(k for k, v in alphanumero.items() if v == keylet_upper) # Calculate encrypted number: (plaintext num + key num) mod 26 encrypted_num = (letnum + keynum) % 26
Step 3: Convert Back to a Letter
Use your dictionary to turn the encrypted number back into a letter:
encrypted_letter = alphanumero[encrypted_num]
Here's the complete, tested version with error handling for invalid inputs:
# Number to uppercase letter mapping alphanumero = {0:'A', 1:'B', 2:'C', 3:'D', 4:'E', 5:'F', 6:'G', 7:'H', 8:'I', 9:'J', 10:'K', 11:'L', 12:'M', 13:'N', 14:'O', 15:'P', 16:'Q', 17:'R', 18:'S', 19:'T', 20:'U', 21:'V', 22:'W', 23:'X', 24:'Y', 25:'Z' } try: # Get plaintext letter and standardize to uppercase inputlet = input("Enter letter to be encrypted: ").upper() letnum = next(k for k, v in alphanumero.items() if v == inputlet) # Get key letter and standardize keylet = input("Enter key letter: ").upper() keynum = next(k for k, v in alphanumero.items() if v == keylet) # Perform Vigenère shift encrypted_num = (letnum + keynum) % 26 encrypted_letter = alphanumero[encrypted_num] print(f"Encrypted letter: {encrypted_letter}") except StopIteration: # Catch cases where input isn't a valid letter print("Oops! Please enter a valid uppercase or lowercase letter.") except Exception as e: # Catch any other unexpected errors print(f"Unexpected error: {str(e)}")
To make this more scalable (like supporting full words later), you could wrap the letter-to-number and number-to-letter logic into helper functions. For example:
def letter_to_num(letter): return next(k for k, v in alphanumero.items() if v == letter.upper()) def num_to_letter(num): return alphanumero[num % 26]
内容的提问来源于stack exchange,提问作者zgraham

