UserInput in Python While loop - python

Following my code which is supposed to take 3 positive integer as input from user. However, it is not working as per expectation.
def getPositiveNumber(prompt):
timeUnits = (input("This is the numnber of time units to simulate > "))
numAtoms = (input("How many atoms should we simulate ? "))
radBeaker = (input("The radius of the beaker is ? "))
while True:
if timeUnits.isnumeric() and numAtoms.isnumeric() and radBeaker.isnumeric():
print("All your values are integers")
break
else:
timeUnits = input("This is the number of units to simulate. >")
numAtoms = input("How many atoms should we simulate ? ")
radBeaker = input("The radius of the beaker is ? ")
return timeUnits, numAtoms, radBeaker
This results in asking the input again after the initial 3 inputs have been placed but i want it to ask again right after the initial part if I put a non number.

There is no point in writing three almost identical code fragments to read three integer numbers. You need one function that gets one number. You can call this function three times or, in fact, as many times as you like:
def get_positive_int(prompt):
while True:
possibly_number = input(prompt + "> ")
try:
number = int(possibly_number)
except ValueError: # Not an integer number at all
continue
if number > 0: # Comment this line if it's ok to have negatives
return number
The function relies on the fact that any string recognized by int() is a valid integer number. If it is, the number is returned to the caller. If it is not, an exception is raised by int() that keeps the loop going.
Example:
>>> get_positive_int("This is the number of units to simulate")
This is the number of units to simulate> ff
This is the number of units to simulate> -10
This is the number of units to simulate> 25
25

Try this:
def getPositiveNumber(prompt):
timeUnits = None
numAtoms = None
radBeaker = None
while True:
timeUnits = input('This is the numnber of time units to simulate > ')
numAtoms = input('How many atoms should we simulate ? ')
radBeaker = input('The radius of the beaker is ? ')
if timeUnits.isnumeric() and numAtoms.isnumeric() and radBeaker.isnumeric():
print 'All your values are integers'
break
return (timeUnits, numAtoms, radBeaker)

You can separate the test to check if the input is a positive integer to a function
def is_positive(n):
"""(str) -> bool
returns True if and only if n is a positive int
"""
return n.isdigit()
Next you can create a function to ask for a positive integer. For this avoid the str.isnumeric method because that returns True for floats as well. Rather, use the str.isdigit method.
def request_input(msg):
"""(str) -> str
Return the user input as a string if and only if the user input is a positive integer
"""
while True:
retval = input(msg)
if is_positive(retval):
return retval
else:
print("Please enter a positive integer")
request_input will loop forever until a positive integer is received. These simple blocks can be combined to achieve what you want. In your particular case:
def get_user_inputs(prompt):
time_units = request_input("This is the number of time units to simulate > ")
num_atoms = request_input("How many atoms should we simulate ? ")
rad_breaker = request_input("The radius of the beaker is ? ")
return time_units, num_atoms, rad_breaker

Related

Passing variables defined inside of one function into another

Context:
I'm sure this has been asked elsewhere, but the topics I'm finding thus far are more advanced than what I'm doing and only confusing me further. I am a student in an intro to Python course, and am working on a "Lottery Number" assignment. Basically, randomly generate a 7-digit lottery number and print it back out.
That much I get, but I am trying to approach this from a less literal perspective and a more practical one. As in, I want the user to define how many numbers they need and which numbers to choose from. From there, I want the program to generate random numbers that fit the criteria they set.
My instructor wants everything done inside of functions, so I am trying to attempt the following:
What I'm doing:
main() Function - everything inside of here.
get_info() to collect the data from the user, number of digits (MaxDigits), range minimum (MinChoice), range maximum (MaxChoice).
lottery_pick() take the variables and do the lottery thing with them.
I have it "working", but I can only do so if I have lottery_pick() function run inside of the get_info() function. I imagine there has to be a way to define these variables independently, and just pass the variables from get_info() to lottery_pick().
import random
# Define the main function
def main():
get_info()
exit_prompt()
def get_info():
# Set Variables to 0
MaxDigits = 0
# Let the user know what we are doing
print("Let's choose your lottery numbers!")
print("First, How many numbers do you need for this lottery?")
# Request the user input the number of lottery numbers we need
while True:
try:
MaxDigits = int(input('Please enter how many numbers you need to choose: '))
if MaxDigits > 0:
break;
else:
print('Please enter an integer for how many numbers are being drawn. ')
except:
continue
print('Next, we need to know the smallest and largest numbers allowed to choose from')
# Request user input smallest number in range of numbers to pick from.
while True:
try:
MinChoice = int(input('Please enter the lowest number you are allowed to choose from: '))
if MinChoice >= 0:
break;
else: print ('Please enter an integer, 0 or greater for the smallest number to pick from.')
except:
continue
# Request user input largest number in range of numbers to pick from.
while True:
try:
MaxChoice = int(input('Please enter the largest number you are allowed to choose from: '))
if MaxChoice >= 0:
break;
else: print ('Please enter an integer, 0 or greater for the greatest number to pick from.')
except:
continue
# Define the function to actually assemble the lottery number
def lottery_pick(lot_digits, lot_min, lot_max):
numbers = [0] * lot_digits
for index in range(lot_digits):
numbers[index] = random.randint (lot_min, lot_max)
print('Here are your lottery numbers!:')
print(numbers)
# Execute the function - I've not yet figured out how to pass the variables from the get_info
# function to the lottery_pick function without lottery_pick being inside of get_info.
lottery_pick(MaxDigits, MinChoice, MaxChoice)
def exit_prompt():
while True:
try:
# use lower method to convert all strings input to lower-case. This method
# allows user to input their answer in any case or combination of cases.
ExitPrompt = str.lower(input('Would you like to generate another lottery number? Please enter "yes" or "no" '))
if ExitPrompt == 'yes':
main()
elif ExitPrompt =='no':
print('Goodbye!')
exit()
# If an answer other than yes or no is input, prompt the user again to choose to re-run or to exit
# until an acceptable answer is provided.
else:
print('Please enter "yes" to generate another lottery number, or "no" to exit. ')
except:
continue
main()

Error testing python code: TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'

New to Python and am trying to answer a homework problem where: a hospital records how many patients they are dealing with, the required nutrition to be provided to each patient, and then averaging required nutrition per patient after summing the totals.
Now when I'm testing/validating data entry, I see my code is causing errors because of the clumsy way I've tried to solve the problem. When testing, I get this:
TypeError: int() argument must be a string, a bytes-like object or a number, not 'NoneType'
I've tried going through and messing with the return functions, but if it's not there, I think the issue might be with my read_input() functions. I've been messing around with PythonTutor, so I can visualize where the error is...I just have no idea how to get out of this loop and fix it.
my code so far
def validate_positive_patients(n):
try:
n = float(n)
if n <= 0:
print("Please enter a nonnegative number")
return n, False
except ValueError:
print("Please enter a positive integer")
return None, False
return n, True
def read_input(float):
value, positive = validate_positive_patients(input(float))
if not positive:
read_input(float=float)
else:
return value
# rest of code seems to work fine
My code is clumsy, but what I'd really like it to do is only accept int values for 'number of patients', floats for protein, carbs etc., and if there is an entry error initially to not just spit out a None value.
If only computers knew what you wanted them to do instead of what I'm telling it to do :P
Thanks in advance for any help!
By default, Python functions return None.
In your original code, in read_input, if the value entered is not positive, then you never hit a return statement, and accordingly return None.
I've cleaned up your code a little, while attempting to preserve its spirit:
def get_positive_int(message):
while True:
input_value = input(message)
if input_value.isdigit() and int(input_value) > 0:
return int(input_value)
else:
print('Please enter a positive number.')
def get_positive_float(message):
while True:
input_value = input(message)
try:
float_value = float(input_value)
if float_value > 0:
return float_value
except ValueError:
pass
print('Please enter a positive real number.')
def calculate_average(nutrition, total_quantity, total_patients):
average = total_quantity / total_patients
print(f'{nutrition} {average}')
number_of_patients = get_positive_int("Enter number of patients: ")
protein, carbohydrates, fat, kilojoules = 0, 0, 0, 0
for i in range(int(number_of_patients)):
print(f'Patient {i + 1}')
protein += get_float("Amount of protein (g) required: ")
carbohydrates += get_float("Amount of carbohydrates (g) required: ")
fat += get_float("Amount of fat (g) required: ")
kilojoules += 4.18*(4*protein + 4*carbohydrates + 9.30*fat)
print("Averages:")
calculate_average(nutrition = "Protein (g): ", total_quantity = protein,
total_patients = number_of_patients)
calculate_average(nutrition = "Carbohydrates (g): ", total_quantity =
carbohydrates, total_patients = number_of_patients)
calculate_average(nutrition = "Fat (g): ", total_quantity = fat,
total_patients = number_of_patients)
calculate_average(nutrition = "Kilojoules (kJ): ", total_quantity =
kilojoules, total_patients = number_of_patients)
In particular, it is unwise to shadow builtins (using float as a parameter name), and f-strings can make your code easier to read.
You'd be getting None because you're ignoring a value when you call read_input again in the if statement.
The alternative would be to just loop, not call the same function
def read_input(prompt):
positive = False
while not positive:
value, positive = validate_positive_patients(input(prompt))
return value
And I suggest you use while loops so that it continously checks the results
Note that you're also doing return None, False in the first function, so you still should check that value is not None before actually returning a numeric value
Also Check if input is positive integer

Creating a loop and calculating the average at the end

I have an assignment as follows
Write a program that repeatedly asks the user to enter a number, either float or integer until a value -88 is entered. The program should then output the average of the numbers entered with two decimal places. Please note that -88 should not be counted as it is the value entered to terminate the loop
I have gotten the program to ask a number repeatedly and terminate the loop with -99 but I'm struggling to get it to accept integer numbers (1.1 etc) and calculate the average of the numbers entered.
the question is actually quite straightforward, i'm posting my solution. However, please show us your work as well so that we could help you better. Generally, fro beginners, you could use the Python built-in data types and functions to perform the task. And you should probably google more about list in python.
def ave_all_num():
conti = True
total = []
while conti:
n = input('Input value\n')
try:
n = float(n)
except:
raise ValueError('Enter values {} is not integer or float'.format(n))
if n == -88:
break
total.append(n)
return round(sum(total)/len(total),2)
rslt = ave_all_num()
Try the following python code. =)
flag = True
lst=[]
while(flag):
num = float(raw_input("Enter a number. "))
lst+=[num]
if(num==-88.0): flag = False
print "Average of numbers: ", round( (sum(lst[:-1])/len(lst[:-1])) , 2)
enter code hereThank you for the prompt replies. Apologies. This is the code i was working on:
`#Assignment2, Question 3
numbers=[]
while True:
num=int(input("Enter any number:"))
if num==float:
continue
if num==-88:
break
return print(" the average of the numbers entered are:",sum(numbers)/len(numbers)`

Python function returns None after checking if user input is valid

I've just started learning programming some time ago and been playing with Python a bit. I wrote a small program that rolls dice based on user input (number of sides on the die and number of dice). Here's the code:
from random import randrange
def number_of_sides():
n = input("How many sides? ") # Get input from the user
if n.isdigit(): # Check if the input is a digit
n = int(n) # If it is, turn it into an integer
return n # And return the value of n
else:
print("Invalid input. ") # If test returns false, rerun function
number_of_sides()
def number_of_dice():
m = input("How many dice? ") # Get input from the user
if m.isdigit(): # Check if the input is a digit
m = int(m) # If it is, turn it into an integer
return m # And return the value of m
else:
print("Invalid input. ") # If test returns false, rerun function
number_of_dice()
def play_again() -> object: # Checks if user answered yes or no, then reruns everything or exits with exit code 0
answ = input("Do you want to play again?(yes/no) ")
if answ == "yes":
dice_roll()
elif answ == "no":
print("Ok then")
return True
else:
print("Input invalid, trying again")
play_again()
def dice_roll(): # sides - for number of sides, dice - for number of dice.
sides = number_of_sides() # Whatever number the function returns
dice = number_of_dice() # Whatever number the function returns
results = [] # empty list, here is where results will be appended
for i in range(1, dice + 1): # That returns values for each dice specified in the dice variable
throw = randrange(1, sides + 1)
results.append(throw)
results_str = " | ".join(str(i) for i in results) # Turn the list into string, separate results with a pipe
print(results_str) # Print the results of throws
play_again() # Ask the user to play again
dice_roll()
Everything works ok when I provide valid input (so digits like 6 and 6 for sides and dice), it crashes, however, when I try providing invalid input first. For some reason the number_of_sides() and number_of_dice() functions return None when they're first fed invalid input and then crash the code in the for loop in the dice_roll() function:
How many sides? a
Invalid input.
How many sides? 6
How many dice? 6
Traceback (most recent call last):
File "<directory>/dice_roll.py", line 48, in <module>
dice_roll()
File "<directory>/dice_roll.py", line 41, in dice_roll
throw = randrange(1, sides + 1)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Process finished with exit code 1
I tested these functions separately and they seem to be working fine. This snippet:
def number_of_sides():
n = input("How many sides? ")
if n.isdigit():
n = int(n)
print(n, ", ", type(n))
return n
else:
print(n, ", ", type(n))
number_of_sides()
Returns str if you provide a string and int if you provide it with digits. I would like to know what may be causing this weird behaviour.
The problem is that you are calling number_of_dice recursively, but you ignore its result. You should replace the recursive call with:
return number_of_dice()
or even better, get rid of recursion by using a simple while loop:
def number_of_dice():
while True:
m = input("How many dice? ") # Get input from the user
if m.isdigit(): # Check if the input is a digit
m = int(m) # If it is, turn it into an integer
return m # And return the value of m
else:
print("Invalid input. ")
The same, obviously, holds for the other function.
I seem that the functions number_of_sides() and number_of_dice() only return a valid value when the first input is correct otherwise they loop themselves but the new input will not be returned to the main function.
I think recursivity is not good in that case.
You could transform number_of_dices like this :
def number_of_sides():
nb_sides = input("How many sides? ")
while (nb_sides.isdigit())==False:
print("Invalid input. ")
nb_sides=input("How many sides? ")
return int(nb_sides)
For your information, you can also use :
import pdb
pdb.set_trace()
to pause the code in a specific line
"return" statement from your fail case is missing in the 2 statements
from random import randrange
def number_of_sides():
n = input("How many sides? ") # Get input from the user
if n.isdigit(): # Check if the input is a digit
n = int(n) # If it is, turn it into an integer
return n # And return the value of n
else:
print("Invalid input. ") # If test returns false, rerun function
return number_of_sides()
def number_of_dice():
m = input("How many dice? ") # Get input from the user
if m.isdigit(): # Check if the input is a digit
m = int(m) # If it is, turn it into an integer
return m # And return the value of m
else:
print("Invalid input. ") # If test returns false, rerun function
return number_of_dice()
def play_again() -> object: # Checks if user answered yes or no, then reruns everything or exits with exit code 0
answ = input("Do you want to play again?(yes/no) ")
if answ == "yes":
dice_roll()
elif answ == "no":
print("Ok then")
return True
else:
print("Input invalid, trying again")
play_again()
def dice_roll(): # sides - for number of sides, dice - for number of dice.
sides = number_of_sides() # Whatever number the function returns
dice = number_of_dice() # Whatever number the function returns
results = [] # empty list, here is where results will be appended
for i in range(1, dice + 1): # That returns values for each dice specified in the dice variable
throw = randrange(1, sides + 1)
results.append(throw)
results_str = " | ".join(str(i) for i in results) # Turn the list into string, separate results with a pipe
print(results_str) # Print the results of throws
play_again() # Ask the user to play again
dice_roll()

Using random.randint help in python

The following code is my attempt at simulating a lottery.
import random
def lottery(numbers):
lottoNumbers = [randint('0,100') for count in range(3)]
if numbers == lottoNumbers:
print('YOU WIN $10,000')
else:
print('YOU LOSE,DUN DUN DUNNN!')
return numbers
def main():
numbers = int(input('Enter a number: '))
if numbers == lottoNumbers:
numbers = lottery(numbers)
else:
numbers = lottery(numbers)
main()
Hey guys I've gotten this far with the help you've given me. I'm trying to write the code so that 3 lotto numbers at random will be chosen. Then the user must enter 3 of his/her own lotto numbers. If they get all 3 correct then they win the whole prize, if they get the 3 numbers but not in the correct order they win some of the prize. Obviously if they guess all wrong then a print statement would state that. What I'm confused about is how can I write the code so that the user can enter 3 numbers to try matching the random lottery numbers. I also want to print the 3 lottery numbers after the user inputs his/her choices. Any ideas guys?
Thanks for your help everyone.
You seem a bit confused about what the role of the arguments in a function are. You've said that your randm function takes the argument "number", but then you haven't actually used it anywhere. The next time number appears, you've assigned it a completely new value, so any value passed to randm isn't actually being used.
Also, the function is trying to return x, when x hasn't been assigned within the function. Either you already have a global variable called x already defined, in which case the function will just return that variable, or the function will just fail because it can't find the variable x.
Here's a quick example I've done where you pass their three numbers as a list as an argument to the function.
import random
theirNumbers=[5,24,67]
def checkNumbers(theirNumbers):
lottoNumbers = []
for count in range(3)
lottoNumbers.append(random.randint(0,100))
winning = True
for number in theirNumbers:
if not each in lottoNumbers: winning=False
if winning == True: print("Winner!")
There are a few things wrong with your implementation, to name a few:
if you are trying to compare the output of the function randm to x, you will need to include a return value in the function, like so:
def randm():
return return_value
You appear to be printing all the values but not storing them, in the end you will only end up with the final one, you should attempt to store them in a list like so:
list_name = [randint(0,100) for x in range(x)]
This will generate randint(0,100) x times in a list, which will allow you to access all the values later.
To fix up your code as close to what you were attempting as possible I would do:
import random
def randm(user_numbers):
number = []
for count in range(3):
number.append(random.randint(0, 100))
print(number)
return user_numbers == number
if randm(x):
print('WINNER')
If you are looking for a very pythonic way of doing this task,
you might want to try something like this:
from random import randint
def doLotto(numbers):
# make the lotto number list
lottoNumbers = [randint(0,100) for x in range(len(numbers))]
# check to see if the numbers were equal to the lotto numbers
if numbers == lottoNumbers:
print("You are WinRar!")
else:
print("You Lose!")
I'm assuming from your code (the print() specifically) that you are using python 3.x+
Try to post your whole code. Also mind the indentation when posting, there it looks like the definition of your function would be empty.
I'd do it like this:
import random
def lottery():
win = True
for i in range(3):
guess = random.randint(1,100)
if int(raw_input("Please enter a number...")) != guess:
win = False
break
return win
Let so do this in few steps.
First thing you should learn in writing code is to let separate pieces of code( functions or objects) do different jobs.
First lets create function to make lottery:
def makeLottery(slotCount, maxNumber):
return tuple(random.randint(1,maxNumber) for slot in range(slotCount))
Next lets create function to ask user's guess:
def askGuess(slotCount, maxNumber):
print("take a guess, write {count} numbers separated by space from 1 to {max}".format(count = self.slotCount, max = self.maxNumber))
while True: #we will ask user until he enter sumething suitable
userInput = raw_input()
try:
numbers = parseGuess(userInput,slotCount,maxNumber)
except ValueError as err:
print("please ensure your are entering integer decimal numbers separated by space")
except GuessError as err:
if err.wrongCount: print("please enter exactly {count} numbers".format(count = slotCount))
if err.notInRange: print("all number must be in range from 1 to {max}".format(max = maxNumber))
return numbers
here we are using another function and custom exception class, lets create them:
def parseGuess(userInput, slotCount,maxNumber):
numbers = tuple(map(int,userInput.split()))
if len(numbers) != slotCount : raise GuessError(wrongCount = True)
for number in numbers:
if not 1 <= number <= maxNumber : raise GuessError(notInRange = True)
return numbers
class GuessError(Exception):
def __init__(self,wrongCount = False, notInRange = False):
super(GuessError,self).__init__()
self.wrongCount = wrongCount
self.notInRange = notInRange
and finally function to check solution and conratulate user if he will win:
def checkGuess(lottery,userGuess):
if lottery == userGuess : print "BINGO!!!!"
else : print "Sorry, you lost"
As you can see many functions here uses common data to work. So it should suggest you to collect whole code in single class, let's do it:
class Lottery(object):
def __init__(self, slotCount, maxNumber):
self.slotCount = slotCount
self.maxNumber = maxNumber
self.lottery = tuple(random.randint(1,maxNumber) for slot in range(slotCount))
def askGuess(self):
print("take a guess, write {count} numbers separated by space from 1 to {max}".format(count = self.slotCount, max = self.maxNumber))
while True: #we will ask user until he enter sumething suitable
userInput = raw_input()
try:
numbers = self.parseGuess(userInput)
except ValueError as err:
print("please ensure your are entering integer decimal numbers separated by space")
continue
except GuessError as err:
if err.wrongCount: print("please enter exactly {count} numbers".format(count = self.slotCount))
if err.notInRange: print("all number must be in range from 1 to {max}".format(max = self.maxNumber))
continue
return numbers
def parseGuess(self,userInput):
numbers = tuple(map(int,userInput.split()))
if len(numbers) != self.slotCount : raise GuessError(wrongCount = True)
for number in numbers:
if not 1 <= number <= self.maxNumber : raise GuessError(notInRange = True)
return numbers
def askAndCheck(self):
userGuess = self.askGuess()
if self.lottery == userGuess : print "BINGO!!!!"
else : print "Sorry, you lost"
finally lets check how it works:
>>> lottery = Lottery(3,100)
>>> lottery.askAndCheck()
take a guess, write 3 numbers separated by space from 1 to 100
3
please enter exactly 3 numbers
1 10 1000
all number must be in range from 1 to 100
1 .123 asd
please ensure your are entering integer decimal numbers separated by space
1 2 3
Sorry, you lost
>>> lottery = Lottery(5,1)
>>> lottery.askAndCheck()
take a guess, write 5 numbers separated by space from 1 to 1
1 1 1 1 1
BINGO!!!!

Categories

Resources