What does this line of the poem refer to? Well, there are several examples and interpretations one could give, but today I would to interpret this line with reference to the idea of readability.
We wrapped up part one by talking about a function that contains no defenses against misuse. To jog your memory, here's the code again:
In [9]:
def net_force(mass, acceleration):
return mass * acceleration
Literally this function takes two objects and returns mass * acceleration; But what does that actually mean? And why should we care?
Well, the meaning of this code is implicit, the author just assumes you are going to understand what it does and how to use it. The premise of today's lecture however is that this code can be rewritten to be more explicit, and being explicit is generally to be prefered.
To be more precise, the code make two implicit assumptions:
Regarding the second point above I'm not going to explain why this is a problem today (for that explanation, see lecture on Operator Overloading), but I will propose a few possible fixes. But first things first, lets talk physics!
To People with a modest background in Physics it is pretty obvious all we are doing is taking the formula for force, f=ma, and putting it in code form.
But to understand the problem with the code, we need to imagine talking to someone that NEVER took a physics lesson at school before. For this person, they understand that we are multiplying two numbers (i.e. Mass, Acceleration) but they have not concept of what the result actually means. In short, the code only returns force if you know the physics, for everyone else the function return simply returns two numbers multiplied together.
In short, the code is being implicit but the poem tells us to be explicit. Alright, let's try and fix that now...
In [1]:
def net_force(mass, acceleration):
force = mass * acceleration
return force
print(net_force(10,10))
This code does one more thing that makes things more explicit. instead of returning:
Mass * Acceleration
we now return:
Force
...And the line above the return statement clearly assigns force to 'Mass * Acceleration'. So now even those readers without the physics background understand the meaning behind what we are doing; the function isn't merely returning A times B, its returning force.
So, we have succesfully made our code more explicit, even readers without an understanding of physics can grasp what the number we are returning actually means.
However, there is a problem with this:
"Do we really want to add code to our function whose sole purpose is to make things readable?"
Honestly that is exactly what we have done in this case, defining and then returning force simply adds an unnecessary step. Unnecessary lines of code harms readability which is ironic since we only added this unnecessary line to make the code more readable!
As a matter of fact there is a solution to this problem, we could just add an in-line comment like this:
# ...and now we return force...
return mass * acceleration
Such a comment makes the code more explicit, but doesn't add unnecessary code. So already this looks like a better solution. It turns out though we can do even better than a comment, we can add a ‘docstring’:
In [ ]:
def net_force(mass, acceleration):
"""
Calculates f=ma, returns force.
We assume mass & acceleration are of type int/float.
"""
return mass * acceleration
The above code has a new concept to talk about. The red text encased in triple quotes is called a docstring, it is a special type of string that Python Programmers use to communicate with each other. Usually docstrings contain information about how the function works, and how to use it. Such is the case here. Docstrings can also serve as another way to write comments that span several lines. The Syntax is really simple:
"""
{Text}
"""
The docstring above tells use that the function expected us to pass in integers/floats, and it also mentions what it is supposed to do (i.e. calculate f=ma). In short, adding documentation has helped make our function much more explicit. And for what it is worth, adding docstrings to all your functions is generally regarded as good practice.
Its often a good idea to mention the expected 'types' of input. If you expect somebody to pass in numbers then say so. If you the code is supposed to work with strings then say so; Explicit is better than implicit.
Being explicit about what your code expects can prevent bugs, for example:
In [15]:
def net_force(mass, acceleration):
"""
Calculates f=ma, returns force.
We assume mass & acceleration are of type int/float.
"""
return mass * acceleration
print(net_force("10", 10))
This output might surprise you (and I'll explain why this happens in later lectures). Notice that the function net_force says it expects numbers. We passed in a string and an integer. And so, if we are using the function in an unexpected/unintended way should we surprised when things do not work as we expect?
So docstrings/comments can avoid bugs because they increase the chances that somebody will use some piece of code as it was designed to be used. If only I read the documentation, I would have known to not pass in a string!
Okay, so that explains why we should leave text for other developers to read, but why are Docstrings better than comments? Well, the main reason is that docstrings make for better documentation. For example:
In [13]:
help(int)
we can use the "help" command to get information about a python objects. As a implementation detail, "help" will return the docstring of the function. Thus, if we use docstrings then other developers can call 'help' on our functions to find out what they do. Cool right?
In [10]:
def add_eight_1(x):
"""
Takes a integer x, and returns x + 8
"""
return x + 8
help(add_eight_1)
In [11]:
def add_eight_2(x):
# Takes a integer x, and returns x + 8
return x + 8
help(add_eight_2)
In [ ]: