inputs not validated properly - python

Right now, I am zooming into a section of my code as below :
qty = int(input('enter current quantity :'))
if qty != int:
print('input is not integer')
in the above chunk, i passed '5' yet
it returns 'input is not integer'...
So i tried running the below code:
type(qty)
After running this, the output is 'str'
does anyone know what can I change so that the inputs properly gets converted?
i tried....
#notice how i removed the space between '=' and 'int'
qty =int(input('enter current quantity :'))
if qty != int:
print('input is not integer')
this time, the same message appears... HOWEVER,
type(qty)
returns that it has successfully converted to 'int'

That's not how you check the type of instance of an object.
You should use isinstance function if you care about the inheritance OR use type if you want to check specifically for a type.
Option 1:
x = 5
if isinstance(x, int):
# Do some logic here
Option 2:
x = 5
if type(x) is int: # Use "is" and not "==", since classes are singletons!
# Do some logic here
Regarding your code:
qty = int(input('enter current quantity :'))
if qty != int:
print('input is not integer')
If qty is provided by user and can be casted into an int
the condition is false, cause e.g. 5 is NOT equal class int.
If qty is left blank then an empty string is passed to the int() and ValueError: invalid literal for int() with base 10: '' is raised.
So the condition is NEVER true.
Side notes:
In python it's common to use EAFP (easier ask for forgiveness than for permission) more often than LBYL (look before you leap), so you shouldn't care what is the type, do your logic and handle possible raised errors
python uses ducktyping concept, so if it quacks like a duck and walks like a duck treat it like one (doesn't matter it it actually is a duck or not), more technically if an entity implements a particular interface you don't have to check for its type per se
for more info about type vs isinstance look here What are the differences between type() and isinstance()?
please do read about difference between "==" comparison and "is" operator

if qty != int is not how you check for the type of a variable. Instead, try:
if not isinstance(qty, int):
...
Note, however, that if the user doesn't enter an integer i.e.:
int("hello world")
Then a ValueError will be thrown, meaning the code will never reach your if statement. A better solution is to wrap the user input in a try-except statement

Related

Python cannot ignore str when input is int()

SO I have a program where the input is in an int, but when the user enters a str, the program crashes. I want the program to ignore any str that it can't convert to an int. I tried declaring a variable that said type(input). Then, I added an if statement:
if (variable) == str:
print(oops)
Remember I declared the input as an int. So I don't know.
Thank you.
You can use exceptions for this. You get a Value Error when you try to convert a string input to int. By enclosing it in a try clause here, it is telling that if a Value Error arises, you can ignore it. For now I've used the pass statement, but if there's something else you want to do if the input is a string, you can add it there.
try:
x = input()
value = int(x)
print(value)
except ValueError:
pass
You can use try-except to handle the case.
try:
value = int(input())
except ValueError:
print("Input is not an int type")
pass
In python you can call isinstance() on the variable passing the datatype you want to check for-
sent = 'your_string'
num = 24
isinstance(sent, int) # returns False
isinstance(num, int) # returns True
isinstance(sent, str) # returns True
isinstance(num, str) # returns False
Applicable with other data types too!
So a simple-
if not isinstance(str, int):
print('Only integer values accepted')
if my_input.isdigit():
int(my_input)
# your code goes here
else:
print('oops')
exit() # maybe you like to exit
You could do something like
input_number = input("Enter your number")
if type(eval(input_number)) == int:
#Do stuff
else:
print('Sorry that is an invalid input')
I also noticed you said
Remeber I declared the input as an int
Python is not statically typed, so you don't have to declare a variable as a certain data type, and along with that even if you do, their type can still be changed.
You can use str.isnumeric() to check if input is of int type or not. THis is better than using try..except
input_number = input("enter a number: ")
if input_number.isnumeric():
input_number = int(input_number)
# do magic

easier way to do this IF statement to differentiate type of variable passed to function

Still very new to python. I have refactored a piece of coe and extracted the following code to a new method. It works fine but in search of more pythonic ways I feel the IF clauses are maybe clumsy. Essentially the function may be passed either a str or a number as the variable 'second_option' As a result there is a subtle difference to the next line.
I tried a conditional assignment but it seemed to get upset over the data frame elements of this.
def create_crossover_data(self, indicator, second_option, market_data):
if type(second_option) == str:
market_data['position'] = market_data[indicator] > market_data[second_option]
else:
if type(second_option) == int or float:
market_data['position'] = market_data[indicator] > second_option
market_data['pre_position'] = market_data['position'].shift(1)
market_data.dropna(inplace=True) # dropping the NaN values
market_data['crossover'] = np.where(market_data['position'] == market_data['pre_position'], False, True)
market_data.drop(columns=['position', 'pre_position'])
Generally, in python, it is prudent to use isinstance instead of type. Type only checks that the exact type matches while isinstance checks if our object in question inherits from the given type.
Assuming your second if statement is trying to determine if the variable in question is a number you can use. This method: How can I check if my python object is a number?
Which in your case would be
else:
if isinstance(second_option,numbers.Number):
market_data['position'] = market_data[indicator] > second_option
There is a way in Python to check the type of a variable: isinstance().
Here you have a couple of options to rewrite your code:
def create_crossover_data(self, indicator, second_option, market_data):
if isinstance(second_option, str):
threshold = market_data[second_option]
if isinstance(second_option, (int, float)):
threshold = second_option
market_data['position'] = market_data[indicator] > threshold
The next one looks simpler but makes the assumption second_option can only be a number or a string, and that might not be true, so I would add some control to that:
def create_crossover_data(self, indicator, second_option, market_data):
market_data['position'] = market_data[indicator] > second_option if isinstance(second_option, (int, float)) else market_data[second_option]
Also new to this, but I see nothing except else if -> elif

is it bad practice to overwrite a variable in a different datatype python

I was wondering when I was input validating in python whether it is good practice to overwrite a variable in a different data type, example:
x = "initialise"
while x == "initialise":
try:
x = int(input("what is the number "))
except ValueError:
print ("it has to be a number\n")
print (x)
if it is bad practice then can you tell me a different way in which I can input validate this if it is ok then can you help me aswell? thanks.
In your particular example, you should use the special None keyword when initializing a variable without a value.
In general, try not to use the same variable for multiple datatypes.
Is this what you intended to do..?
x = "initialise"
guess_value = None
while guess_value != x:
try:
guess_value = eval(input("what is the number: "))
except NameError:
print ("it has to be a number\n")
print (guess_value)
Regarding the overwriting the data type, it doesn't matter as the variable name being assigned to new data type. Only thing what you need to make sure is that the new data type works for your program.

How to simplify 2 conditions that rely on one another but lead to the same result?

I have a function that accepts an integer year, but I also want the user to be able to pass in the string 'ALL' and still be able to get something back.
I have this ugly piece of code right now:
if type(year) != str or (type(year) == str and year.upper() != 'ALL'):
total_results = self.filterResultsByYear(total_results, year, year2)
Results are filtered by default to the current year, and can be filtered by other years, but if the user wants to not filter, they have to pass in 'all' for the year.
The reason I wrote the above abomination is if I just have if year.upper() != 'ALL' I get a TypeError if I pass in an integer. If I put if type(year) != str and year.upper() != 'ALL' I still get the same error. The above code looks really ugly and I wanted to make it more pythonic. What tools do I have to do this?
Depending on what total_results and year2 are and how you'd like to handle them:
try:
year = int(year)
total_results = self.filterResultsByYear(total_results, year, year2)
except ValueError:
if not isinstance(year, (str, unicode)):
raise # Not string, unicode or coercible to an integer.
if year.lower() == 'all':
# Your logic here.
else:
# String but not 'all'. Exception handling.
Bye the way, to check for class equivalency one uses isinstance(object, class) or isinstance(object, (class 1, class 2, ...)).

Python: If is running even when condition is not met

import imaplib, re
import os
while(True):
conn = imaplib.IMAP4_SSL("imap.gmail.com", 993)
conn.login("xxx", "xxxx")
unreadCount = re.search("UNSEEN (\d+)", conn.status("INBOX", "(UNSEEN)")[1][0]).group(1)
print unreadCount
if unreadCount > 10:
os.system('ls')
Even when unreadCount is < 10, it runs the command 'ls'. Why?
You might want to coerce that value to an integer, as per:
unreadCount = int (re.search (blah, blah, blah).group (1))
The call to re.search is returning a string and, if you have a look at the following transcript:
>>> x = "7"
>>> if x > 10:
... print "yes"
...
yes
>>> if int(x) > 10:
... print "yes"
...
>>> x = 7
>>> if x > 10:
... print "yes"
...
>>>
you'll see why that's not such a good idea.
The reason you're seeing this (what you might call bizarre) behaviour can be gleaned from the manual at the bottom of 5.3:
CPython implementation detail: Objects of different types except numbers are ordered by their type names; objects of the same types that don’t support proper comparison are ordered by their address.
Since the type of "7" is str and the type of 10 is int, it's simply comparing the type names ("str" is always greater than "int" in an alpha order), leading to some interesting things like:
>>> "1" > 99999999999999999999999
True
>>> "1" == 1
False
That implementation detail was still in effect up until at least 2.7.2. It may have changed in the Python 3000 stream (the clause has certainly been removed from the relevant documentation section), but the documentation there still states:
Most other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program.
So it's probably not something you should rely on.
Try this:
if int(unreadCount) > 10:
os.system('ls')
You're comparing a string to an integer:
>>> '10' > 10
True
This may be shocking; whether the string is coerced to an integer or the integer is coerced to a string, in both cases the result should have been False. The truth is that neither happens, and the ordering is arbitrary. From the language reference:
Most other objects of built-in types compare unequal unless they are the same object; the choice whether one object is considered smaller or larger than another one is made arbitrarily but consistently within one execution of a program.
This will solve your problem:
unreadCount = int(re.search(...).group(1))

Categories