0

When I attempt to run this it says NameError: name 'encrypt' is not defined.

MAX_KEY_SIZE = 26
def getMode():
    while True:
           print('Do you wish to encrypt or decrypt a message?')
           mode = input().lower()
           if mode in "encrypt" 'e' 'decrypt' 'd'.split():
                return mode
           else:
                 print('Enter either "encrypt" or "e" or "decrypt" or "d".')
Roman Marusyk
  • 23,328
  • 24
  • 73
  • 116
Nic Pismiris
  • 1
  • 1
  • 1
  • 1
    Are you using Python 2 or Python 3? The `print` functions look like 3, but the `NameError` you're getting would come from 2's version of `input`. (See [progo's answer](https://stackoverflow.com/questions/38631474/38631721#38631721) for why it matters.) – Kevin J. Chase Jul 28 '16 at 09:10
  • It appears that this is Python 2 code, with a `from __future__ import print_function` that isn't shown here. – Kevin J. Chase Jul 28 '16 at 09:53

4 Answers4

2

From what I understand of your code, 'encrypt' is a string value. You need to create a list with your required string values and check whether the mode variable matches with a value in that list.

MAX_KEY_SIZE=26
def getMode():
    while True:
        mode=input().lower()
        if mode in ['encrypt','e','decrypt','d']:
            return mode
        else:
            print('Enter either "encrypt" or "e" or "decrypt" or "d".')

If you want to use the .split() method, you could do the following:

if mode in "encrypt e decrypt d".split()
RahulHP
  • 336
  • 4
  • 6
  • or `"encrypt e decrypt d".split()` that wil make the list in place. – alec_djinn Jul 28 '16 at 09:02
  • Additionally, one could do `ALLOWED_ANSWERS = ['encrypt','e','decrypt','d']` and then `if mode in ALLOWED_ANSWERS:` and afterwards `print("Enter either " + " or ".join(ALLOWED_ANSWERS) + ".")` or maybe even `print("Enter either " + " or ".join('"' + i + '"' for i in ALLOWED_ANSWERS) + ".")` – glglgl Jul 28 '16 at 09:04
  • 1
    While this solves _a_ problem, it doesn't solve the `NameError` that Nic Pismiris is encountering. See [pogo's answer](https://stackoverflow.com/questions/38631474/38631721#38631721) for that. (For what it's worth, I fell for this, too.) – Kevin J. Chase Jul 28 '16 at 09:34
1

Gotcha! input tries to eval your input (as such, it's named very misleadingly). Use raw_input for capturing user's wishes in string format.

Basically what input does is it takes raw_input and pipes it to eval: now you're trying to evaluate a string "encrypt" as Python code, so it has the same effect as writing "encrypt" to your file. Naturally that would result in an error because no such variable is introduced anywhere. Both eval and input are pretty dangerous stuff so try not to use them, there's very seldom a real use case for them.

More info on this difference around this site: https://stackoverflow.com/a/15129556/308668

Community
  • 1
  • 1
mike3996
  • 17,047
  • 9
  • 64
  • 80
0
MAX_KEY_SIZE = 26
def getMode(): 
    while True:
        print ('Do you wish to encrypt or decrypt a message?') 
        mode = input().lower()
        if mode in "encrypt" 'e' 'decrypt' 'd'.split():
            return mode 
        else: 
            print('Enter either "encrypt" or "e" or "decrypt" or "d".')

Hope this is your code.. if Yes, then it should not give any error, also the method you are trying to get the result is supposedly will not solve your purpose, because "encrypt" 'e' 'decrypt' 'd'.split() will give you ['encryptedecryptd'] and you cannot search mode through "in" method that you are trying. Either you can search mode like: if any(mode in s for s in "encrypt" 'e' 'decrypt' 'd'.split()): or you can store"encrypt" 'e' 'decrypt' 'd'` in list and then use "in" method to match with the user's input.

Hope it helps..

justjais
  • 344
  • 3
  • 13
  • This does not solve the `NameError` produced by Python 2's `input`. (Nic Pismiris did not specify which version of Python he was using, but Python 3's `input` won't produce that error.) – Kevin J. Chase Jul 28 '16 at 09:44
  • Also, `if any(mode in s for s in ....split()):` will iterate over the same list-of-one-string, making it effectively the same as `if mode in 'encryptedecryptd':`. So it will return `True` if `mode` is `'encrypt'`, but also if it's `'ted'` or `'cry'` or `'edecr'`. Your last option --- a list of allowed strings --- is much more precise. – Kevin J. Chase Jul 28 '16 at 09:49
  • Thanks Kevin for the use case where **"any"** fails, also looking to the code, its definite that the code is written in **python 3**, also using input() will give **"NameError"** as in case of **python 3** if user need to take input of string or character, user need to enclose the input in to either in **double quote/single quote**, So in above case, input should be: **"encrypt"** rather than only **encrypt**. – justjais Jul 28 '16 at 10:22
  • You mean Python 2, not Python 3, right? 3's `input` always returns a string (same as 2's `raw_input`). It was **2**'s `input` that tried to evaluate whatever the user typed. – Kevin J. Chase Jul 28 '16 at 10:27
  • I meant python **3** only, and python **3** `input()` doesn't return string all the time like the `raw_input()` of python **2**, e.g. if the user in 3 using `input()` gives the input as 1, its type will be **int** in contrast to 2's `raw_input()` which irrespective of the user's input take everything as **string**. – justjais Jul 28 '16 at 10:55
  • Sorry, but that's just not true. [Python 3's `input` _always_ returns a string](https://docs.python.org/3/library/functions.html#input) if it returns at all. Try it... Entering a `1` when prompted by `input` will return the _string_ `'1'`, not the integer `1`. I just tried it myself (Python 3.1 and 3.5), and my experience matches the docs --- always a string, never anything else. – Kevin J. Chase Jul 28 '16 at 11:11
  • 1
    Yes, you are right. I got it confused with python 2.* `input()` function. – justjais Jul 28 '16 at 13:00
0

Expanding on pogo's answer, which is correct...

What surprised me (and apparently many others) is that the cluster of strings in the if mode in ...: line is not a syntax error.

if mode in "encrypt" 'e' 'decrypt' 'd'.split():

Those strings are all compile-time constants, so string literal concatenation glues them into one string before execution starts:

>>> "encrypt" 'e' 'decrypt' 'd'
'encryptedecryptd'

The split() method is then called on that string, which by chance does not contain any whitespace. The return value is a list containing a single string:

>>> "encrypt" 'e' 'decrypt' 'd'.split()
['encryptedecryptd']

The in operator won't complain about being given a string (mode) and a list of strings, but it will return False for every value of mode except one... which no one is ever likely to type:

>>> 'encrypt' in ['encryptedecryptd']
False
>>> 'encryptedecryptd' in ['encryptedecryptd']
True
Kevin J. Chase
  • 3,856
  • 4
  • 21
  • 43