Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
condensing try except
#1
There must be a way to achieve this type of code. As it is its violating everything about DRY...


also is there any way to condense try except statements within 1 while True looks?
example

while True:
	try:
		foo = str(input('enter a string: '))
		bar = int(input('enter a bar num > '))
		moo = int(input('enter moo num > '))
		break
	except ValueError:
		if foo != str(foo):
			print('must be a word...')
		else:
			print('number please')
		continue
there must be a way to tighten this up...
Reply
#2
your code can be simplified to just this
foo = input('enter a string: ') #input already returns a string
while True:
    try:
        bar = int(input('enter a bar num > '))
        moo = int(input('enter moo num > '))
    except ValueError:
        print('you must input a number only')
        continue
    break
input() returns a string, so its obviously a string.
assume bar and moo will be input correctly as ints, and catch it in try/except if not
Recommended Tutorials:
Reply
#3
If you fear to violate the DRY principle, write a function
from functools import partial

def typed_input(prompt, type, errmsg):
    while True:
        v = input(prompt)
        try:
            v = type(v)
        except ValueError:
            print(errmsg)
        else:
            return v
        
int_input = partial(typed_input, type=int,
                    errmsg='An integer is required, try again...')
float_input = partial(typed_input, type=float,
                    errmsg='A real number is required, try again...')

if __name__ == '__main__':
    foo = input('enter a string: ')
    bar = int_input('enter a bar num > ')
    moo = int_input('enter a moo num > ')
Reply
#4
@Gribouillis
I think this is very elegant. Can you give me a quick run down of the what the function is doing. I don't quite understand it.

I'm not very familiar with the functools module. My first impression is that this is similar to a wrapper (aka hard coded decorator...which I've only recently gotten to...)

I'm stuck on the concept of the definition name used as a leading argument when the int and float objects are instantiated...

I understand the if clause at the bottom. That is crystal clear. I'm lost on the interplay between function and object here....would u pls run through it (even if only briefly)...thx
Reply
#5
(Jan-18-2018, 05:20 PM)mepyyeti Wrote: Can you give me a quick run down of the what the function is doing

The function typed_input() takes three arguments, it can be used this way
n = typed_input('enter integer: ', int, 'An integer is required, try again...')
It then asks repeatedly a string by printing enter integer: , then it tries to convert the string to a python integer by calling int() and if it fails, it prints the error message and asks again.

The idea of using int and errmsg in the parameters is that the function can be used to input other datatypes by using for example float or complex in the arguments.

The fuctools.partial() callable is the python implementation of partial function application. It takes a function and some arguments and it creates a new callable with fewer arguments, so partial(type_input, type=int, errmsg='No, try again...') creates a new callable which takes a single prompt argument, the same interface as input()

This looks a little like meta-programming, because we use a type as a parameter, which is not very frequent. If you look carefully, you'll notice that the only hypothesis on the 'type' parameter is that is is a callable taking one argument and throwing ValueError. This can be used to input more general data. For exemple suppose I want the user to enter a probability, which is a real number between 0 and 1, I can write
def probability(arg):
    p = float(arg)
    if not (0.0 <= p <= 1.0):
        raise ValueError(('Invalid value for probability():', arg))
    return p

proba_input = partial(typed_input, type=probability,
                    errmsg='A probability is required, try again...')

qux = proba_input("Give me a probability > ")
This will prompt the user until she enters a number between 0 and 1 !
Reply
#6
(Jan-18-2018, 06:20 PM)Gribouillis Wrote:
(Jan-18-2018, 05:20 PM)mepyyeti Wrote: Can you give me a quick run down of the what the function is doing

The function typed_input() takes three arguments, it can be used this way
n = typed_input('enter integer: ', int, 'An integer is required, try again...')
It then asks repeatedly a string by printing enter integer: , then it tries to convert the string to a python integer by calling int() and if it fails, it prints the error message and asks again.

The idea of using int and errmsg in the parameters is that the function can be used to input other datatypes by using for example float or complex in the arguments.

The fuctools.partial() callable is the python implementation of partial function application. It takes a function and some arguments and it creates a new callable with fewer arguments, so partial(type_input, type=int, errmsg='No, try again...') creates a new callable which takes a single prompt argument, the same interface as input()

This looks a little like meta-programming, because we use a type as a parameter, which is not very frequent. If you look carefully, you'll notice that the only hypothesis on the 'type' parameter is that is is a callable taking one argument and throwing ValueError. This can be used to input more general data. For exemple suppose I want the user to enter a probability, which is a real number between 0 and 1, I can write
def probability(arg):
    p = float(arg)
    if not (0.0 <= p <= 1.0):
        raise ValueError(('Invalid value for probability():', arg))
    return p

proba_input = partial(typed_input, type=probability,
                    errmsg='A probability is required, try again...')

qux = proba_input("Give me a probability > ")
This will prompt the user until she enters a number between 0 and 1 !

Working on partials, I'm noticing that the variable qux isn't really necessary. Suppose: the user is ask to input probability 3 times.

why wouldn't I just use
proba_input = partial(typed_input, type=probability, errmsg='prob reqd')
?
I mean at its extreme end I could just reuse the same variable and just overwrite the value. I'm not quite clear on the benefit of
foo = bar(original_func_as_place_holder,para1='a',para2='b')
when I have already set up
bar = partial(original_func_as_place_holder,para1='a',para2='b')
.

I mean since foo is a variable I can't just use it as a function every time I ask for probability input. I have to rewrite the partial anyway.
Reply
#7
I don't understand your objection. One can ask the user to input 3 different probabilities by calling proba_input() 3 times
for i in range(3):
    qux = proba_input('Give me the {}-th probability: '.format(i))
The line with partial is only a way to define a new callable (proba_input) by specifying two arguments for typed_input.

Consider the following example
>>> def is_multiple_of(a, b):
...     return b % a == 0
... 
>>> is_multiple_of(5, 15)
True
>>> is_multiple_of(5, 14)
False
>>> from functools import partial
>>> is_even = partial(is_multiple_of, 2)
>>> is_even(14)
True
>>> is_even(13)
False
>>> is_even(12)
True
>>> is_even(9)
False
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020