[Tutor] ValueError

Peter Otten __peter__ at web.de
Wed May 4 11:43:19 CEST 2011


Kushal Kumaran wrote:

> On Tue, May 3, 2011 at 5:31 PM, Peter Otten <__peter__ at web.de> wrote:
>> <snip>
>>
>> Also you should make the try...except as narrow as possible
>>
>> try:
>> centimeters = float(centimeters)
>> except ValueError as e:
>> print e
>>
>> is likely to catch the float conversion while with many statements in the
>> try-suite you are more likely to hide a problem that is unrelated to that
>> conversion.
>>
> 
> I would have expected it to be the other way.  If you cannot
> reasonable expect to continue after an exception, then the try block
> should extend all the way across the block of code you want to skip.
> In your snippet, what if some code later is relying on the
> 'centimeters' variable having a useful float value?  IMO,
> encapsulating small bits of code in try ... except blocks really makes
> code written using exceptions look ugly.

Instead of repeating what Alan said I'll give you a side-by-side example:
 
import sys

def make_raw_input(stdin, stdout):
    def raw_input(message):
        stdout.write(message)
        s = stdin.readline()
        stdout.write(s)
        return s.rstrip("\n")
    return raw_input

if not sys.stdin.isatty():
    raw_input = make_raw_input(sys.stdin, sys.stdout)

_conversion_factors = {"in": (2.54, "cm"),
                       "cm": (1/2.54, "in")}

def thorough_convert():
    default_unit = "in"
    while True:
        s = raw_input("Enter a length in inches or cm (like '7 in' or '1.3 
cm') ")
        if not s:
            print "That's all, folks"
            break

        try:
            value, unit = s.split(None, 1)
        except ValueError as e:
            value = s
            unit = default_unit
            print "using default unit:", unit

        try:
            conversion_factor, target_unit = _conversion_factors[unit]
        except KeyError:
            print "unrecognized length unit: {!r}".format(unit)
            continue
        default_unit = unit

        try:
            value = float(value)
        except ValueError as e:
            print e
        else:
            target_value = value * conversion_factor
            print "{} {} --> {} {}".format(value, unit,
                                           target_value, target_unit)

def simple_convert():
    while True:
        try:
            s = raw_input("Enter a length in inches or cm (like '7 in' or 
'1.3 cm') ")
            if not s: break
            value, unit = s.split()
            factor, target_unit = _conversion_factors[unit]
            print s, "-->", float(value)*factor, target_unit
        except Exception as e:
            print e

        
if __name__ == "__main__":
    if "--simple" in sys.argv:
        convert = simple_convert
    else:
        convert = thorough_convert
    if "--demo" in sys.argv:
        from StringIO import StringIO
        raw_input = make_raw_input(StringIO("""\
1 cm
2 in
3 x
4

"""), sys.stdout)
    convert()


Let's run the demo:

$ python2.7 inch.py --demo --simple
Enter a length in inches or cm (like '7 in' or '1.3 cm') 1 cm
1 cm --> 0.393700787402 in
Enter a length in inches or cm (like '7 in' or '1.3 cm') 2 in
2 in --> 5.08 cm
Enter a length in inches or cm (like '7 in' or '1.3 cm') 3 x
'x'
Enter a length in inches or cm (like '7 in' or '1.3 cm') 4
need more than 1 value to unpack
Enter a length in inches or cm (like '7 in' or '1.3 cm')

$ python2.7 inch.py --demo --thorough
Enter a length in inches or cm (like '7 in' or '1.3 cm') 1 cm
1.0 cm --> 0.393700787402 in
Enter a length in inches or cm (like '7 in' or '1.3 cm') 2 in
2.0 in --> 5.08 cm
Enter a length in inches or cm (like '7 in' or '1.3 cm') 3 x
unrecognized length unit: 'x'
Enter a length in inches or cm (like '7 in' or '1.3 cm') 4
using default unit: in
4.0 in --> 10.16 cm
Enter a length in inches or cm (like '7 in' or '1.3 cm')
That's all, folks
$

While thorough_convert() is three times as long as simple_convert() and both 
do almost the same I'd argue that the user experience is significantly 
improved by better error messages and smarter defaults.




More information about the Tutor mailing list