The instructions: Write a function validate_input(string) which takes a command string in the format 'command arg1 arg2' and returns the pair ('command', [arg1, arg2]), where arg1 and arg2 have been converted to floats. If the command is not one of 'add', 'sub', 'mul', or 'div', it must raise InvalidCommand. If the arguments cannot be converted to floats, it must raise InvalidCommand.
Typical inputs and outputs:
validate_input('add 2 3') -> ('add' [2. , 3.])
validate_input('hahahaha 2 3') -> Raises InvalidCommand()
validate_input('add six 3') -> Raises InvalidCommand()
Here is my code:
class InvalidCommand(Exception):
pass
def validate_input(string):
"""
validate_input(str) -> (str, [float])
If string is a valid command, return its name and arguments.
If string is not a valid command, raise InvalidCommand
Valid commands:
add x y
sub x y
mul x y
div x y
Arguments x and y must be convertable to float.
"""
# your code here
inlist = string.split(' ')
commands = []
strdigits = []
floats = []
output = []
for x in inlist:
if x.isdigit():
strdigits.append(x)
else:
commands.append(x)
for x in commands:
try:
x == 'add' or x == 'sub' or x == 'mul' or x == 'div'
output.append(x)
except ValueError:
raise InvalidCommand(ValueError)
for x in strdigits:
try:
float(x)
floats.append(float(x))
except ValueError:
raise InvalidCommand(ValueError)
output.append(floats)
return tuple(output)
When I test it on the values where it is supposed to raise InvalidCommand(), It tells me "Your code must raise InvalidCommand(). But my code does. I checked for typos and there are not any. So did I do the whole raising statement wrong? Please show me how to fix this. Thanks.
This line:
x == 'add' or x == 'sub' or x == 'mul' or x == 'div'
does nothing. It does not actually do anything with the result of your test, certainly it does not raise ValueError.
What you need is something like this:
if x.lower in ('add', 'sub', 'mul', 'div'):
output.append(x)
else:
raise InvalidCommand('unknown command: {}'.format(x))
Your code works for the numeric arguments because float() can raise ValueError if it is given a string that can not be converted to a float:
>>> float('abcd')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: could not convert string to float: abcd
Also, why you are passing ValueError as an argument to your custom exception? You might like to pass an error string that describes the nature of the error, e.g.
raise(InvalidCommand('arguments must be numeric: {}'.format(x))
or, you can pilfer ValueError's message:
try:
float(x)
floats.append(float(x))
except ValueError as exc:
raise InvalidCommand(exc)
You're making this way more complicated than it needs to be.
class InvalidCommand(Exception):
pass
def validate_input(datastr):
"""
validate_input(str) -> (str, [float])
If string is a valid command, return its name and arguments.
If string is not a valid command, raise InvalidCommand
Valid commands:
add x y
sub x y
mul x y
div x y
Arguments x and y must be convertable to float.
"""
inlist = datastr.split()
if len(inlist) != 3:
raise InvalidCommand('Bad command length: ' + str(len(inlist)))
x = inlist[0]
if x in ('add', 'sub', 'mul', 'div'):
cmd = x
else:
raise InvalidCommand('Bad command verb: ' + x)
floats = []
for x in inlist[1:]:
try:
floats.append(float(x))
except ValueError:
raise InvalidCommand('Bad command arg: ' + x)
return cmd, floats
#Test
data = [
'add 1 2',
'sub 3.0 2.0',
'mul 4.5 1.5',
'div 8 4',
'add 1 2 3',
'fred 2 3',
'add a b',
'sub 1 c',
]
for s in data:
try:
print(validate_input(s))
except InvalidCommand as e:
print(repr(s), e)
output
('add', [1.0, 2.0])
('sub', [3.0, 2.0])
('mul', [4.5, 1.5])
('div', [8.0, 4.0])
'add 1 2 3' Bad command length: 4
'fred 2 3' Bad command verb: fred
'add a b' Bad command arg: a
'sub 1 c' Bad command arg: c
I've changed the parameter of the validate_input function because string is the name of a standard Python module, so it can be confusing to use it for a simple variable name. And if you want to use that module then shadowing its name like that can lead to annoying bugs.
I did the same question for my uni subject csse1001. What I did was this:
# your code here
lst = string.split(' ')
commands = ['add', 'sub', 'mul', 'div']
if lst[0] not in commands:
raise InvalidCommand()
if len(lst) != 3:
raise InvalidCommand()
try:
arg1 = float(lst[1])
arg2 = float(lst[2])
return(lst[0], [arg1, arg2])
except ValueError:
raise InvalidCommand()
This worked for me.
Related
I want to create a dictionary that has keys and values, values has to be 3 elements long list. the first is a string that asks for input, the second a function that check a condition and the third a string to print if the condition is false
dict = {
'input 1': ['number > 10', def check(n): pass if n > 10 else raise ValueError, 'the number must be gratere than 10'],
'input 2': ['3 words', def check(text): pass if len(text) == 3 else raise ValueError, 'must be 3 words'],
'input 3': ['name', def check(text, name_list): pass if text in name_list else raise ValueError, 'the name has to be one of them '.format(x = name_list)]
}
for i in dict:
while True:
text = input(dict[i][0])
try:
dict[i][1](text)
break
except ValueError:
print(dict[i][2])
I know this is very strange but the dict is very long and with very different conditions.
I don't even know how can I pass multiple arguments to the funcs that need more than one
This does what you ask. Take some time to note the changes I've made here.
Note that the functions must all accept the same parameters.
def check_num( val ):
n = int(val )
if n <= 10:
raise ValueError( 'the number must be greater than 10' )
def check_3( val ):
if len(val.split()) != 3:
raise ValueError( 'must be 3 words' )
def check_name( val ):
if text not in name_list:
raise ValueError( 'the name must e one of' + (' '.join(name_list)) )
data = {
'input 1': ['Enter number', check_num],
'input 2': ['Enter 3 words', check_3],
'input 3': ['Enter a name', check_name]
}
name_list = ['Bill', 'Ted', 'Tom']
for i,info in data.items():
while True:
text = input(info[0]+': ')
try:
info[1](text)
break
except ValueError as e:
print( e )
If all your functions take only the input text as argument, make your function return a bool value:
dict = {
'input 1': ['number > 10', lambda n: n > 10, 'the number must be gratere than 10'],
'input 2': ['3 words', lambda text:len(text) == 3, 'must be 3 words'],
'input 3': ['name', lambda text: text in name_list, 'the name has to be one of them '.format(x = name_list)]
}
for i in dict:
while True:
text = input(dict[i][0])
res = dict[i][1](text)
if res:
break
else:
print(dict[i][2])
There is no easy way to make your third function work, because it requires a different number of arguments, I suggest setting name_list as a global variable.
Use lambda to create function expressions in the list, not def. But lambda can only contain a single expression to evaluate and return; pass and raise are statements, not expressions.
So you'll need to define these functions outside the dictionary, then reference them there.
And since you never use the dictionary keys, iterate over the values().
Don't use dict as a variable name, it overwrites the built-in class with that name.
name_list will need to be a global variable. All the check functions can only take 1 argument, since the loop has no way of knowing that some functions require additional arguments. It just passes the input text.
def check_greater_10(n):
if n <= 10:
raise ValueError
def check_3_words(text):
if len(text.split()) != 3:
raise ValueError
def check_name_list(text):
if text not in name_list:
raise ValueError
mydict = {
'input 1': ['number > 10', check_greater_10, 'the number must be greater than 10'],
'input 2': ['3 words', check_3_words, 'must be 3 words'],
'input 3': ['name', check_name_list, 'the name has to be one of them: {x} '.format(x = name_list)]
}
for prompt, check, error in mydict.values():
while True:
text = input(prompt)
try:
prompt(text)
break
except ValueError:
print(error)
get input using realdlines() function:
import sys
inputx = sys. stdin. readline()
print(inputx)
for no of lines use sys.stdin.readlines() but it must be given under for loop with range
I am practicing with error handling and I have a question. can you make it so the error messages in the assert will be displayed in the except block right now if a error occurs only 'error' is printed and not the actual error message
try:
a = int(input('Please enter the first number it must be >= 200' + '\n' + '(note the sum of both numbers must be <=300)'))
b= int(input('please your second number it must be <= 50'))
c = a + b
assert a >=200 and isinstance(a, int), 'invalid entry for a must be <= 200 and a number'
assert b<=50 and isinstance(b, int), 'invalid entry for b must be <=50 and a number'
assert c <= 300, 'The sum of your numbers is >300'
except ValueError
print('error')
else:
print('All in range')
Add an except that catches the AssertionError and prints it:
except AssertionError as e:
print(e.args[0] if e.args else "error")
cmds = ['time']
while True:
inp = input('::> ')
sinp = inp.split()
if str(sinp[0]) in cmds:
print('mkay.')
Would I be able to get the position of the item in the table, if the name and input match? Thanks!
UPDATE: Here's my updated code:
cmds = ['k', '1']
while True:
inp = input('>>> ')
sinp = inp.split()
try:
if str(sinp[0]) in cmds:
cmds.index(sinp)
print(sinp)
except ValueError:
print('Unknown Command')
It's returning me 'Unknown Command' whenever I type in k or 'k'. Same goes for 1, however '1' works. What's the reason for this?
Oh god. Sorry to trouble you guys, I did just sinp instead of sinp[0] for .index. ouch.
UPDATE: it's not accepting '1' or 1. even though it's in the cmds table.
You can use you_list.index(the_item)
cmds = ['time', 'yep']
while True:
inp = input('::> ')
sinp = inp.split()
if str(sinp[0]) in cmds:
print('mkay.')
print cmds.index(inp)
Output:
::> time
mkay.
0
::> yep
mkay.
1
::>
If cmds is the "table", then cmds.index gives you the position in which the matching string is.
The index() method of the list is what you need.
>>> cmds = ['e', 'r', 't']
>>> cmds.index('e')
0
>>> cmds.index('t')
2
>>> cmds.index('y')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: 'y' is not in list
Make sure you put it in a try, except block in case the command is not found.
For example,
inp = str(input('::> '))
sinp = inp.split()
print("You are trying to run command:", sinp[0])
try:
print(cmds.index(sinp[0]))
except ValueError:
print("Command not recognised")
I have an exception from which I'm trying to get args, but if fails.
print hasattr(e, 'args')
print type(e.args)
print hasattr(e.args, '1')
print hasattr(e.args, '0')
print '1' in e.args
print '0' in e.args
print 1 in e.args
print 0 in e.args
print e.args[0]
print e.args[1]
This prints:
True
<type 'tuple'>
False
False
False
False
False
False
Devices not found
4
You simply use the in operator:
>>> try:
... raise Exception('spam', 'eggs')
... except Exception as inst:
... print inst.args
... print 'spam' in inst.args
...
('spam', 'eggs')
True
If your code is returning False then most likely 1 wasn't an argument to the exception. Perhaps post the code where the exception was raised.
You can check if the tuple has positions 0 to N by doing len.
You can check the length of your tuple:
t = 1, 2, 3,
if len(t) >= 1:
value = t[0] # no error there
...or you can just check for an IndexError, which I'd say is more pythonic:
t = 1, 2, 3,
try:
value = t[4]
except IndexError:
# handle error case
pass
The latter is a concept named EAFP: Easier to ask for forgiveness than permission, which is a well known and common Python coding style.
Hello everyone I need some help with this question
Write a function named safe_input (prompt, type)
that works like the Python input function,
except that it only accepts the specified type of input.
The function takes two arguments:
prompt: str
Type: int, float, str
The function will keep prompting for input until correct input of the specified type is
entered. The function returns the input. If the input was specified to be a number (float or int), the value returned will be of the correct type; that is,the function will perform the conversion.
The default for a prompt is the empty string.
The default for the type is string.
Heres what I have:
safe_input = input(str("Enter a String Type you want to check: "))
test = safe_input("this is a string")
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input("this is a string",int)
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input("this is a string",float)
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input(5)
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input(5,int)
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input(5,float)
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input(5.044)
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input(5.044, int)
print ('"{}" is a {}'.format(test,type(test)))
test = safe_input(5.044, float)
print ('"{}" is a {}'.format(test,type(test)))
def safe_input (prompt, type=str):
if (type == int):
while (True):
try:
# check for integer or float
integer_check = int(prompt)
# If integer, numbers will be equal
if (prompt == integer_check):
return integer_check
else:
print("They are not equal!!")
return integer_check
except ValueError:
print ("Your entry, {}, is not of {}."
.format(prompt,type))
prompt = input("Please enter a variable of the type '{}': "
.format(type))
Does anyone have any idea what I am doing wrong here? My friend and I been working on this for hours.
UPDATE: I get errors such as:
File "C:\Users\Thomas\Desktop\ei8069_Lab9_Q4.py", line 28, in <module>
test = safe_input("this is a string")
TypeError: 'int' object is not callable
Traceback (most recent call last):
File "C:\Users\Thomas\Desktop\ei8069_Lab9_Q4.py", line 28, in <module>
test = safe_input("this is a string")
TypeError: 'float' object is not callable
Just my two cents.
First, read your assignment more carefully, your method isn't exactly what they want.
And you are using a lot of unnecessary conditions. Your function could be much more simplier, like this:
def safe_input(prompt, type_=str):
if(type_ not in (str, int, float)):
raise ValueError("Expected str, int or float.")
while True:
test = input(prompt)
try:
ret = type_(test)
except ValueError:
print("Invalid type, enter again.")
else:
break
return ret
Try not to use builtin functions like type for variable names. They would override builtins and can cause a lot of headache later on.
Why do you have this line:
safe_input = input(str("Enter a String Type you want to check: "))
At the beginning of your program. You should have the definition of the function instead, but you have it at the end.
Solution: remove that bogus line and move the definition of the function to the top of the program.
Explanation: When you run that line, it will ask the user for something, and that (say 42 will be assigned to safe_input. Then you try to use that as a function, but hey, 42 is an integer, and that cannot be called.