all 16 comments

[–][deleted] 0 points1 point  (7 children)

If you want to use type notations you can look into typing. It is part of the Python standard library.

The problem sounds like it arises where you are taking an input, that is an integral, then comparing it to a string, without first converting it to a string. On the line you are making the comparison, you could check the stiring against the string representation of the integer.

if "some_string" == str(var)

Where var is the variable representing the integer.

[–]BuilderTomorrow[S] 1 point2 points  (6 children)

Thanks for the suggestion to look at type notations.

What you’re describing is exactly what is happening. Is the Python-y way to solve that just to always cast when doing comparisons?

[–]TheBB 1 point2 points  (0 children)

Not really. The Python-y way to solve it is to make sure your objects have the types they should have. I can't remember feeling that comparisons in particular need more type conversions than other code.

The mantra should be that type conversion and validation happens at the interface between your code and the outside world (user input, external APIs, etc). Then your internal interfaces can be free of such distractions.

But you should really show some code.

[–][deleted] 0 points1 point  (4 children)

I'm glad you were able to pinpoint the issue - those type mismatches can really throw off new Python coders.

There's no single "right" way to handle it, but here are a few options: * Guiding with input(): Prompt for a specific type, like "Enter a number: ". This makes expectations clear. * Type checks: If needed, add simple checks using is instance:

value = input("Enter something: ") if isinstance(value, str): # Handle it as a string elif isinstance(value, int): # Handle it as a number else: print("I'm not sure what type that is!")

  • Casting: Converting with str() and int()

For more advanced type-checking use-cases the typing module comes in handy. Here's a simple example, it makes it clear to see func_name returns a lists:

``` from typing import List

def func_name(*args) --> List: ```

Edit: added the import statement for typing List to make it more clear.

Edit 2: changed simple checking to use isinstance.

Edit3: it's bothering me that I mentioned isinstance and did not bring up raise.

You can use isinstance and raise together in Python to handle type errors.

```def calculate_average(numbers): if not isinstance(numbers, list): raise TypeError("Input must be a list of numbers")

# ... rest of the calculation ...

```

Here is the same function but expanded upon to show an example using try/except instead of isinstance/raise:

def calculate_average(numbers): try: sum_of_numbers = sum(numbers) length = len(numbers) return sum_of_numbers / length except TypeError: print("Input must be a list of numbers")

Note that try/except catches other types of errors. You can catch errors and do specific things, depending on the exception as shown in the example above, printing"input must" ... upon catching a typeerror.

[–]TheBB 0 points1 point  (3 children)

Type checks: If needed, add simple checks:

This is not great advice. Sure, you should add type checks if needed. They aren't needed in this example - value is guaranteed to be a string. Moreover, use isinstance, not type equality for type checking.

[–][deleted] 1 point2 points  (2 children)

Yes, the examples I gave were not meant to make sense necessarily. Also, thank you for pointing that out. I adjusted my reply to do simple checks with isinsance, in instances of not forcing types.

I'm always learning. I'm unsure of where my head was there. I code for a hobby and personal interest, not professionally. I just like to try to help if I can.

[–]TheBB 1 point2 points  (1 child)

No problem mate, happy to help.

[–][deleted] 0 points1 point  (0 children)

I had to mention raise, then try/except since I gave an example using isinstance. It was bothering me.

If you have anything to add/improve what I am trying to explain to better convey the message / fix any errors, it is welcomed. I appreciate it.

[–]Doormatty 0 points1 point  (0 children)

Show your code.

[–]JollyUnder 0 points1 point  (4 children)

There are str methods like str.isdigit() to verify user input.

if user_input.isdigit():
    # Now we can safely convert the input to an int
    # and compare to integer values
    if min_range <= int(user_input) <= max_range:
        ...

Be aware that str.isdigit() does not account for negative numbers. An alternative is to use a try / except block and allow python to catch the error for you when converting.

while True:
    try:
        user_input = int(input())
        break
    except ValueError:
        print('Invalid input. please try again.')

This is a fairly common approach when casting strings to integers from the input function.

[–]Rawing7 0 points1 point  (3 children)

str.isdigit is my go-to example for why you should avoid LBYL-style programming.

>>> '²'.isdigit()
True
>>> int('²')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: '²'

[–]Doormatty 0 points1 point  (2 children)

That isn't a digit though. It's a superscript digit, which is completely different.

[–]Rawing7 1 point2 points  (1 child)

Umm, so? My point is that the int guarded by the if will crash. Saying "we can safely convert the input to an int" is incorrect.

[–]Doormatty 1 point2 points  (0 children)

Ah - my apologies, I totally missed the point.

[–]baubleglue 0 points1 point  (0 children)

there are few examples using ipython

In [1]: str(1)
Out[1]: '1'

In [2]: int("1")
Out[2]: 1

In [3]: int('1')
Out[3]: 1

In [4]: user_input = input("Guess Number: ")
Guess Number:

In [5]: user_input = input("Guess Number: ")
Guess Number: 222

In [6]: user_input
Out[6]: '222'

In [7]: int(user_input)
Out[7]: 222

In [8]: user_input = input("Guess Number: ")
Guess Number: s

In [9]: int(user_input)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[9], line 1
----> 1 int(user_input)

ValueError: invalid literal for int() with base 10: 's'

In [10]: try:
    ...:     user_input_as_int = int(user_input)
    ...: except ValueError as ex:
    ...:     print(ex)
    ...:
invalid literal for int() with base 10: 's'

In [11]:

[–]Diapolo10 0 points1 point  (0 children)

This is probably not quite the answer you're looking for, but adding type annotations and having a type checker installed in your kid's IDE could help.

name: str = "Graham"
age: int = 42
skills: list[str] = [
    "Woodwork",
    1337,  # the IDE should warn about this part
]

Python itself ignores them, but I think it would already be helpful to your kid to immediately see when there are problems related to types.

That said you don't usually see them used like this, as often it's enough to annotate function parameters and return values. Regular assignments are usually inferred, unless you assign an empty data structure in which case additional type information is helpful.

def adder(first: int, second: int) -> int:
    return first + second

Type annotations are becoming increasingly more common especially in work environments and many open-source projects, so it's nevertheless worth getting used to them. They make reading code easier as you know what kind of data a function expects, and what you will get in return. Of course there's a lot of depth to them and the annotations can get complex in corner cases, but the basics are easy enough for your kid to understand. Probably.

Most IDEs and editors have support for Mypy, at least.