--- tags: python-course title: lesson-05 --- # How do I use that function? [![hackmd-github-sync-badge](https://hackmd.io/ROKEyWk0TuyYENPaa-Zcsw/badge)](https://hackmd.io/ROKEyWk0TuyYENPaa-Zcsw) :::info :bulb: Useful programs are correct and documented. This lesson introduces the engineering principles of testing, type annotations, and documentation. Personas: Teacher is Nina, student is James. ::: :::success :movie_camera: VIB background fading to course title slide. James and Ninas smiling faces appear. ::: :::warning :notes: Upbeat intro music ::: **James**: Help! I have a fractional number that I want to round to the nearest `0.1`, not the nearest whole number. If I use the round function I only get it rounded to the nearest whole number. I want it to give me `3.1`, not `3`. How do I do that? :::success :movie_camera: Animation in the background showing `round(3.14159)` being evaluated. ::: **Nina**: This is where the `help` function comes in useful. Functions in Python can document themselves for exactly this purpose. So let's have a look at the help for `round` before we dive into this further. :::success :movie_camera: Animation in the background showing `help(round)`. ::: **James**: Yeah, if I pass in a second argument to the `round` function, then I get what I want. That's so easy! **Nina**: `help` is very useful in these situations. And it is thanks to the person who wrote the `round` function that they also took time to write down how to use their function. You should provide this service to yourself when you write your own functions. **James**: To myself? **Nina**: Sometimes the programs you write won't be used by other people, but they will be used by you... In 3 months... after you've forgetten how to use the programs you wrote. So you should write helpful messages to your future self about how to use them. **James**: How do I do that? **Nina** (over demonstration): First of all. We've already talked about comments. Leave notes for yourself when you write something even remotely unobvious. But also, when you write your function you can include a "docstring" and this docstring is what is going to be displayed by the `help` function. :::success :movie_camera: Fade to a new notebook cell. ```python= def greet(name): "Greet 'name' in English." return "Hello, " + name ``` ::: **Nina**: Once you've defined a docstring, you can pass the function to `help` to see the docstring. :::success :movie_camera: Show the output of `help(greet)`. ::: **James**: So anything I put in the docstring is displayed the same by the help function. That's useful because it means I don't even need to look for where I defined the function to see how to use it. I can also ask for help from all of the built-in functions when I need to. **Nina**: You can improve this for yourself even more by providing type annotations. Type annotations document the types of inputs a function accepts, and the type of the return value. :::success :movie_camera: Re-write `greet` in the background ::: ```python= def greet(name: str) -> str: "Greet 'name' in English." return "Hello, " + name ``` **Nina** (Over animation highlighting the parts of the expression): This says that the variable `name` should contain a string and the function "greet" should return a string. :::success :movie_camera: Back to hosts. ::: **James**: How is that useful? **Nina**: There are a several advantages type hints give you. First they show up in the `help` function. They can also be used by programming editors to provide helpful suggestions when using your function. Finally, type annotations automatically verified to check the correctness of your program. **James**: With all of this documentation, future me surely knows how to use the `greet` function by now. What do you mean by "correctness"? **Nina**: Your function and it's documentation are not very useful if it doesn't work correctly. A correct function produces outputs that you expect given your inputs. **James**: How can I be confident that the code I write produces correct results? Is there a way to keep any confidence I have in those results as I make changes to it? **Nina**: For such a trivial function you can probably immediately see that it is correct. But for anything more complex, you can "test" your code. Having computations inside functions makes testing them very easy: you just need to provide inputs for which you know the correct outputs and check that your function produces these same correct outputs. **Nina** (speaking over typing out tests): I can use the assert keyword for this check! ```python= assert greet("") == "Hello, " assert greet("James") == "Hello, James" assert greet("Nina") != "Hello, James" ``` **James**: In principle, there are an infinite number of strings you could provide as input, why did you choose to test those specific inputs? :::success :movie_camera: Show testing comic. ::: **Nina**: Programming errors often occur at so called edge cases. For a string this might be the empty string, or a very long string. For a number these might be zero or a large negative or positive value. I also tested a specific expected name and the greeting it produces. And I also eliminated the possibility that it will produce "Hello, James" for all non-empty inputs. **James**: When I run these tests nothing is displayed. Is that right? **Nina**: If all of these tests pass successfully nothing will be displayed. If one fails, though, Python will display an `AssertionError` and stop immediately. :::success :movie_camera: Show tests passing then show a failure. ::: **James**: My tests don't test every single possible input but I am more confident that my function is correct. I can change my program too and be confident that I haven't made a mistake if my tests still pass. My tests can also be used by my future self as examples for how to use the function being tested, so they're also a form of documentation. Thanks for your help Nina! **Nina**: You're welcome. **Nina** (to the camera): In this lesson we've demonstrated 3 techniques you can use to increase your confidence when working with code. Document the functions you write using docstrings so you can return to your document in the future, understand it, and change it if necessary. Secondly, you can annotate your values with types so you figure out how to use them. And finally, test your code to give yourself the confidence to change it without breaking it. :::success :movie_camera: Fade to VIB logo slide. ::: :::warning :notes: Upbeat outro music :::