[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