Effective Python — Practice Problem— Don’t return None from a function

Bruce Krayenhoff
3 min readFeb 5, 2018

--

This is an #exercise I created, to practice what I’m learning in the book #Effective #Python: 59 Specific Ways to Write Better Python by Brett Slatkin.

This exercise is for “Item 14: Prefer Exceptions to returning None”

The exercise code is at the bottom.

Reading the book may help give context.

You can also reach me on twitter: @wbrucek

Schedule your practice over time

I recommend you practice this a few times (spread out over time) to internalize the lesson. Some ways to schedule this practice are:

  1. Send a link to this post to: 3days@followupthen.com, 14days@followupthen.com
  2. Get Anki and create a flash card with a link to this post — but only practice it a few times!
  3. Have one editor window (I use PyCharm) with all your files open, and search it regularly for dates in a special format. You can see in the code below that I put the dates (and priorities) “P1t180205 P2t180216”, so I’ll redo this problem on or shortly after Feb. 5th and 16th. I also use these date annotations to schedule other things (like adding documentation later, making this post after I had done the exercise a few times myself)!

Fancy Formatting in PyCharm

Here is a screenshot from my PyCharm. You can setup this kind of formatting with regexes under “Settings => Editor => TODO”

The Full Exercise Code

Copy this code to your editor to do the problem yourself!

# __Q:  P1t180205 P2t180216 
# __Q: Improve this code - what works better than returning None:
# __Q: Have a look at the ANS afterwards!

def divide(a, b):
if b == 0:
return None
else
:
return a/b

res = divide(4, 0)
if not res:
print(f"PC:KEYolxC: 0 for divisor!")
else:
print(f"\nres is [[{res}]]")


if "HINT - fold until needed" == False:
def divide(a, b):
if b == 0: # __c What if passing complex numbers? Something that's equivalent to a 0 in the complex plane wouldn't match here.
# __c Returning None is risky:
# What if they do an "if divide(0, 0):"?
# They might think the result is evaluating to False because the return value is "0", not "None" indicating 0-division!
# Without looking inside the function, it isn't clear that None would be returned, indicating 0-division
return None
else
:
return a / b


res = divide(4, 0)
if not res: # __c ERROR - This is also triggered when 0 returned
print(f"PC:KEYolxC: 0 for divisor!")
else:
print(f"\nres is [[{res}]]")
if "ANS - fold until needed" == False:
# Effective Python, Item 14 - Prefer exceptions to returning None
def divide(a, b):
""" Divides a/b

Throws a ValueError if b is 0 -> It's important to document this!

:param a: Numerator
:param b: Denominator
:return: a/b
"""
try:
return a / b # __c It will still show this exception when run! Have a look!
except ZeroDivisionError as e:
raise ValueError("parameter b should be non-zero") from e


try: # __c Use this handling code, rather than testing that None returned.
res = divide(4, 0)
except ValueError as e:
print(f"PC:KEYolxC: 0 for divisor!")
else:
print(f"\nres is [[{res}]]")

--

--

Bruce Krayenhoff
Bruce Krayenhoff

Written by Bruce Krayenhoff

I'm a machine learning scientist, a father, and a geek :). I'm passionate about personal improvement and improving the world.

Responses (1)