Day 16
For next time
- MP4 is due next class, but the class time will be devoted to starting the Final Team Project (not MP4). Be sure to attend (and let us know in advance if you can’t).
- Check out Think Python Chapter 19 “The Goodies” if you haven’t already. No assigned Reading Journal.
Documentation
In case we haven’t said it enough, proper documentation is vital to your work. As a general guideline, you should have:
- Docstring/header comment at the top of each module (file) explaining what it does
- Docstring for each class, method, and (nontrivial) function
- Comments for sections of code that are complex enough to need explanation
Documenting Python Code: A Complete Guide is a helpful reference here (stuff on type hinting is interesting, but probably not necessary for your projects).
One cool feature of docstrings is that Python can use them to automatically generate documentation.
The tool that does this is called
pydoc,
and it is what is used when you call help()
in Python.
Exercise:
Autogenerate documentation for your project using pydoc:
pydoc path/to/my_project.py
This will open a help file based on your docstrings (use q to quit). Make sure this help file would be adequate for someone using your code - try showing it to someone not on your team. Add to your documentation based on this feedback.
Style and Lint
As you move to more polished code that other people will read and contribute to, style and consistency count.
For a poetic take on “Pythonic” code, try typing import this
in Python.
The most definitive Python style guide is PEP8 (Python Enhancement Proposals are the mechanisms by which the language grows). It has a list of guidelines along with concrete examples - definitely worth a read.
Checking style rules is a good job for a computer, and one tool you can use to do this for you is pylint. “Linting” is the process of checking code without actually running it (think about picking pieces of lint off your sweater). You can even set this up to run continuously in your text editor as you write code.
Linting can even help you catch bugs. Check out this pylint output for “Bad Kangaroo” from Think Python chapter 17.
...
C: 1, 0: Missing module docstring (missing-docstring)
W: 4, 4: Dangerous default value [] as argument (dangerous-default-value)
C: 12, 8: Variable name "t" doesn't conform to snake_case naming style (invalid-name)
...
Using mutable types as a default argument? Dangerous indeed - watch out!
Exercise:
Run pylint
or pycodestyle
(formerly called pep8
) on your project code and analyze the results.
You don’t need to fix everything, but it’s best to know what rules you’re breaking and why.
Organizing large projects
As projects grow in scope and complexity, organization becomes more important. Fortunately, Python makes it fairly easy to add structure as you go.
Interactive
>>> print("Hello, SoftDes!")
In Python it’s quick and easy to get started and test your ideas interactively in the shell. Unfortunately these explorations are ephemeral, and it’s difficult to make changes and run the program again, so we quickly move beyond this stage.
Script
Your first Python script may be simply code from an interactive session pasted into a .py
file so that you can edit and re-run it (as well as share it with team mates). This type of code is often linear (lacking reusable functions) and disorganized (a first draft).
Program
We consider a Python program to be a more evolved version of a script, with defined functions, classes, documentation, etc.
Modules
As your program gets bigger, grows beyond what can comfortably fit in one file.
To create a module in Python, you simply write a .py
file as always.
Code in the module can then be imported from other modules using the filename (minus .py
).
As a side-note, this is why we typically put all code to be run inside an if __name__ == "__main__": ...
block at the bottom of the file. This way it will be run if the module is run by itself, but not if it is imported by another program.
Packages
For really big projects, you may even grow beyond a single directory. Python allows you to organize your modules into directories and refer to them as packages.
All you need to do is place a (possibly empty) file called __init__.py
in the folder along with your Python module files. Note: Your code for this class may never get quite this big and that’s ok. From a style perspective I would consider this going a bit too far with organization for the BrickBreaker example shown.
Read about Python modules for all the details.
We’ve added some more organization to the BrickBreaker example repository showing how a project might gradually evolve through these steps. Browse through the git history to see the changes over time.
Exercise:
Think about and sketch out how you would reorganize your project code into modules that group related code.
As a caveat, this type of major refactoring can create lots of merge conflicts if you are not careful. It is best to make sure everything is checked in first, do the exercise together as a team, and have test cases before and after the restructuring to make sure nothing breaks. Now might not be the right time to do the actual reorganization, and that’s OK.