Cre­ate ex­cep­tional code

Never as­sume your code users will al­ways do what you ex­pect. Dar­ren Yates looks at how to make your Python apps ‘fail grace­fully’ us­ing ex­cep­tions.

APC Australia - - Contents -

Writ­ing your own code can be a lot of fun — af­ter all, you’re de­vel­op­ing a prod­uct or ser­vice you or oth­ers will use. The only prob­lem is, you can’t al­ways pre­dict what your end-users will do. For ex­am­ple, you may re­quire a user to type in an ID num­ber. What hap­pens if a num­ber en­tered is out­side the in­dex range? What if it’s a neg­a­tive num­ber or a word? If they try to open up a file that doesn’t ex­ist, what hap­pens next? If not catered for, these ex­am­ples of user in­put in these par­tic­u­lar ap­pli­ca­tions would likely cause app fail­ure. Ex­cep­tion han­dling is the tech­nique of pre-empt­ing in­put prob­lems in a way that’s of­ten termed ‘han­dled grace­fully’. It’s about max­imis­ing the user ex­pe­ri­ence (UX) of your code and Python has built-in func­tions to make this eas­ier to achieve.

SIM­PLE STEPS

When you’re cod­ing for in­put from your users, the first step is to think about the type of in­put you’re af­ter. For ex­am­ple, say you have an app that re­turns the square-root of a dec­i­mal or ‘float­ing-point’ num­ber (grab our source code from apc­mag.com/magstuff and load up ‘square­root.py’):

IM­PORT MATH

while(True): num1­text = in­put(“En­ter a num­ber to get square-root: “) print(math.sqrt (float(num1­text)))

This sim­ple code will in­deed give you the square-root of a num­ber, but it’s also im­por­tant to know the range of in­put for which this func­tion is valid, or in other words, the ‘in­put do­main’. In math­e­mat­ics, the square-root func­tion is only valid for in­te­gers or float­ing-point num­bers greater than or equal to zero (we won’t con­sider com­plex num­bers here), so that’s the in­put do­main for this func­tion.

How­ever, our code has prob­lems. For starters, the in­put is a string — that in it­self isn’t wrong, but what hap­pens if the user types in a word in­stead of a num­ber? Or en­ters noth­ing but the En­ter key? The in­put func­tion will be fine, but the float() func­tion in­side the math.sqrt() func­tion will crash be­cause there is no way to con­vert the string ‘two’, for ex­am­ple, into a float­ing-point num­ber.

ISDECIMAL?

In­ter­est­ingly, while Python comes with a huge range of math­e­mat­i­cal func­tions, one func­tion it doesn’t have is to iden­tify if a string of text is ac­tu­ally a float­ing-point num­ber. Python does have an is­nu­meric() string func­tion, but it only works with dig­its 0 to 9 and doesn’t sup­port a dec­i­mal­point. The so­lu­tion is: def isdecimal(num­ber): try: float(num­ber) re­turn True ex­cept ValueEr­ror:

re­turn False

This com­mon so­lu­tion fea­tures the ‘try/ex­cept’ state­ment, which is a key Python fea­ture al­low­ing you to cap­ture spe­cific er­rors that may oc­cur in the ex­e­cu­tion of your code and to han­dle them ‘with grace’ rather than the full dummy-spit of a pro­gram crash. Here’s how it works — in­side the ‘try’ clause, you put the code you want Python to at least at­tempt to ex­e­cute. If the code works, open the cham­page. If the code fails, the ‘ex­cept’ clause al­lows you to re­cover the sit­u­a­tion.

“Writ­ing your own code can be fun, but you can’t pre­dict what end users will do.”

What’s more, the ‘ex­cept’ clause can han­dle spe­cific er­rors sep­a­rately.

In our isdecimal() func­tion, we start with just the float(num­ber) state­ment. Yep, it looks odd on its own like that, but we’re not re­ally in­ter­ested in the re­sult yet — we just want to know if the value of the ‘num­ber’ pa­ram­e­ter in the isdecimal() func­tion header is a gen­uine float­ing-point num­ber. If the float() func­tion works, the value in ‘num­ber’ is valid and we then re­turn the Boolean value of ‘True’. How­ever, if float(num­ber) fails — for in­stance, it has al­pha­bet char­ac­ters or an empty string — the float() func­tion im­me­di­ately fires off a ‘ValueEr­ror’ flag, which is caught by the ex­cept clause. Since we know at this point the value of ‘num­ber’ isn’t a float­ing-point num­ber, we re­turn ‘False’.

SQUARE-ROOT FIX

We can now com­bine this with Python’s math.sqrt() func­tion, ac­count­ing not only for valid float-point num­bers, but also add in check­ing for num­bers greater than or equal to zero. You can see this in the source code ‘square­root_b.py’. Sure, there’s more code — but it shouldn’t blow up in the user’s face.

CATCH ALL ER­RORS

If you’re not par­tic­u­larly wor­ried about which er­ror type is picked up, you can skip the er­ror type in the ex­cept clause — in­stead of ‘ex­cept ValueEr­ror:’ as we’ve coded, you just use ‘ex­cept:’. It’s a bit like a catch-all ‘else:’ clause in an

Er­ror mes­sages are great when you’re de­bug­ging code, not the end user.

Com­ments that ex­plain ‘ why’ are al­ways a good thing.

Check out the list of built-in ex­cep­tions over at the Python.org web­site.

Did you know the Win­dows client for Drop­box is writ­ten in Python?

Cap­tur­ing the ini­tial er­ror code en­ables you to print it to the screen.

Newspapers in English

Newspapers from Australia

© PressReader. All rights reserved.