0

I'm making a python script for a twitch bot which basically acts as a slot machine. Disclaimer- I'm totally new to python, so please don't kill me.

At the start of the script, I have this code to check if the correct command was typed, check if the first argument is an integer, and check if the user has enough points. The idea is to let them choose an amount to gamble, so the cost line will be changed once i get it working.

if data.IsChatMessage():
    if (data.GetParam(0).lower() == settings["command"]
                    and isinstance((int(data.GetParam(1).lower())), int)
                    and settings["costs"] <= Parent.GetPoints(data.User)):

The input from the chat is always in a string form, even if it's only a number. I'm able to convert that to an int with int(), but if there's nothing or if there's something there other than numbers it crashes the script entirely. How can I keep the script from crashing and instead alert the user they need to input an integer? Thanks!

rxbots
  • 87
  • 1
  • 8
  • 1
    Can you explain in words why you think `isinstance((int(data.GetParam(1).lower())), int)` would work? – Willem Van Onsem Sep 27 '17 at 18:57
  • What exactly do you mean by crash? Do you get an exception? What is it? – kichik Sep 27 '17 at 18:58
  • 2
    Wrap the integer conversion code in a `try ... except` block, and catch the `ValueError` exception that occurs if the string does not represent a valid integer. See [here](https://docs.python.org/3/tutorial/errors.html#handling-exceptions). – user8153 Sep 27 '17 at 18:59
  • 1
    Welcome to SO: you may want to read [ask] and [mcve]. As for your question, you may want to read on exception use in Python (e.g., www.pythonforbeginners.com/error-handling/exception-handling-in-python). – boardrider Sep 29 '17 at 14:03

5 Answers5

2

You write:

isinstance(
    (int(data.GetParam(1).lower())),
    int
)

There are two problems with this fragment:

  • you call the int(..) constructor, and that can fail (error) if you provide it a non-integer (like "foobar18"); and
  • in case the constructor succeeds, then it is guaranteed that the outcome is an int, so the check is useless.

So now the question is what to do. We can construct an advanced check to inspect if a string is indeed an integer, but the problem is that we have to cover multiple cases, and it is easy to forget one.

Python is a language with the idea: EAFP: Easier to Ask for Forgiveness than Permission. It means that the philosophy of Python is to encourage trying something, and in exceptional cases, handle it, than first check if something is an integer.

So wen can write it as:

if data.IsChatMessage():
    try:
        int(data.GetParam(1).lower())  # we try it
        isint = True  # it worked!
    except ValueError:
        # that did not worked out very well, did it?
        isint = False
    if (data.GetParam(0).lower() == settings["command"]
                    and isint
                    and settings["costs"] <= Parent.GetPoints(data.User):
        pass

You better always specify the error you expect to see (ValueError) since if for instance data.GetParam(1) raises another error, you do not per se want to handle it there: it does not mean that data.GetParam(1).lower() is not an integer, it means that data.GetParam(1) has made some (other) error.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
2

After doing a bit of research I think you can use a try/except block to make sure the value given by the user is actually a number.

try:
    i = int(string)
    # normal execution
except ValueError:
    # error msg

I got the answer here: Converting String to Int using try/except in Python

agamemnon
  • 33
  • 3
2

The line isinstance((int(data.GetParam(1).lower())), int) will raise a ValueError exception if data.GetParam(1) is not an integer.

As user8153 suggested, wrap the conversion with try, except block:

try:
    int(data.GetParam(1))
    print(data.GetParam(1) + 'is an integer')
except ValueError:
    print(data.GetParam(1) + 'is not an integer')

Alternatively, you may use data.GetParam(1).isdigit()

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

To check if a string can be casted to an int, simply use:

mystr = 'xx12'
if mystr.isnumeric():
    print('YES!')
else:
    print('NO')
Antwane
  • 20,760
  • 7
  • 51
  • 84
  • That might not work well with Unicode. Documentation states that "Numeric characters include digit characters, and all characters that have the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH". `int(u"\u2155")` throws an exception. – kichik Sep 29 '17 at 22:57
0

You can use python built-in string's method .isnumeric() like this:

>>> "".isnumeric()
False
>>> "a".isnumeric()
False
>>> "5".isnumeric()
True
>>> "55".isnumeric()
True
>>> "55a".isnumeric()
False

but there might be a problem if you also want to check if the number is negative because:

>>> "-5".isnumeric()
False
>>> a = "-4"
>>> a.lstrip("-").isnumeric() and (len(a)-len(a.lstrip("-")) <= 1)
True
>>> a = "--4"
>>> a.lstrip("-").isnumeric() and (len(a)-len(a.lstrip("-")) <= 1)
False

The send part (len(a)-len(a.lstrip("-")) <= 1) checks if there is more than 1 "-"s before the number.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31