0

I am trying to check if my input is a string with try-except block. The function runs without an error. However it checks if the input is an integer, not string. How can I inverse this?

def lexicon(word):
    while True:
        try:
            a=str(input(word))
            print("Input is a string. string = ", a)
        except ValueError:
            print("Oops..Input is not supposed to be a number. Try again!")
    return a
b=lexicon("Enter the word you'd like: ")
dojomaker
  • 209
  • 1
  • 3
  • 8
  • Does this answer your question? [How to find out if a Python object is a string?](https://stackoverflow.com/questions/1303243/how-to-find-out-if-a-python-object-is-a-string) – yahia Nov 17 '20 at 04:49
  • 1
    The `input` function always returns a string, so checking if it is a string is pretty pointless. What exactly do you want to do? – Antimon Nov 17 '20 at 04:52
  • I can't even understand why he has passed the object parameter into input? And @Antimon pointed out correctly that he has converted every word to string so it's pointless to use try-except block for numbers as they are going to be converted to string anyways.. Problem statement is not clear – Raghav Gupta Nov 17 '20 at 04:54
  • @Raghav not only that, but `str(input(...))` is redundant since the return value of `input` is always a string anyway. This code would make sense if it was `int(input(...))`, but OP would need to clarify here. – Antimon Nov 17 '20 at 05:01
  • @Antimon If the input is an integer I want to tell the user that its an error and they need to enter a string as the input – dojomaker Nov 17 '20 at 13:25

2 Answers2

2

If you want specifically to check the value type of the string, you're better off using if/else and isinstance:

if not isinstance(word, str):
    raise TypeError(f"Expecting a string as a value, not {type(word)}.")
else:
    #do something
NotAName
  • 3,821
  • 2
  • 29
  • 44
  • 1
    Note however that Python favours the [EAFP style](https://stackoverflow.com/questions/11360858/what-is-the-eafp-principle-in-python#11360880) ("Easier to Ask for Forgiveness than Permission"), so `try/except` would probably be considered more idiomatic. – Antimon Nov 17 '20 at 05:05
  • @Antimon, I guess, that really depends on what your code is doing. If the variable is being used immediately or very close to where it's declared, `try-except` sounds like a good idea, but if the variable is declared early and is only used much later in execution, I think it's better to do an early check and raise an error. – NotAName Nov 17 '20 at 05:48
  • 1
    Also I think that `if isinstance()` and `if not isinstance()` are both very idiomatic in Python but I may be wrong. – NotAName Nov 17 '20 at 05:50
  • How would you do this with try/except block? – dojomaker Nov 17 '20 at 13:27
  • agree with pavel, better to avoid try/except where it is not needed as it is bad for performance. Testing with isinstance() is very pythonic – Zaffer Jan 15 '23 at 18:58
2

As discussed with user pavel in the comments to his answer, there are two different styles to code for a problem like this: EAFP ("Easier to Ask for Forgiveness than Permission"), meaning that you make your code work on an assumption and take action if it fails; and LBYL ("Look Before You Leap"), in which you first check whether your assumption is true, and then choose the appropriate action to take.

The try/except route is EAFP, since it just executes the code in the try block without bothering to first check whether it would work. If you want to do it in LYBL style, you would explicitly need to ascertain whether the user input is a string representation of a numeric value, and then act accordingly. I'll provide skeletal code for both approaches below. However, note that Python is a little weird compared to other languages in that it seems to have a certain cultural favour for EAFP.

Also, since you are only asking about checking for integers, I will focus on that here. This means that the code will accept floats as valid inputs.

EAFP: try/except

The problem that presumably trips you up is that input always returns a string, so testing if it is a string is nonsensical and will always yield True. However, note that try/except is only an abrigded version of error handling that you can do in Python; the full version is try/except/else/finally. The else block takes effect if no except blocks are executed, and finally is always run at the end. So you could check whether your input is an integer, and make the program raise a failure if that check succeeds. I admit however that this does seem a bit backwards.

try:
    a = int(input())
except ValueError:
    # do whatever
else:
    raise ValueError("Input must not be an integer")

LBYL: if/else

str objects have several methods to test their contents without having to run into errors. For example, .isalpha() checks if all characters are in the alphabet (which returns False however if you include spaces and special characters); isnumeric() checks whether the string is a representation of a number; etc. See a full list here. So depending on what kind of inputs you want to allow, you would need to use one of these methods, or a combination of them, in an if block. The code below essentially does the same thing as the try/except/else version above, using .isdigit() which returns True if all characters in the string are digits (i.e., the same kind of input for which int(a) would succeed).

Note also that I am making use of the new assignment operator := in this code, which is new to Python 3.8. This way, you don't need to explicitly assign the variable a first, however it's a bit harder to catch where the code actually executes an input() function. If you code for backwards compatibility, or don't like the look of this, you'd have to go with the classical a = input() first.

if (a := input()).isdigit():
    raise ValueError("Input must not be an integer")

# do whatever
Antimon
  • 597
  • 3
  • 10