This section contains general tips to improve your experience writing Python.
Listen to your IDE¶
Many popular IDEs, such as PyCharm and VSCode, will tell you if your code has issues in it that may create bugs down the line. Look out for red or yellow squiggles under your code, and hover over these spots to find issues in your code. Learning to pay attention to these squiggles can save you hours of debugging trying to find out why something isn't working.
6.101 in Spring 2023 introduces Pylint and Black. Pylint can help you spot errors and bad code style in your code, while Black formats your code into a common style that's more readable.1 The "Command Line" reading can help you install these tools on your computer.
In VSCode, Pylint and Black can both be used with the official Python extension.
Once you've installed this extension, you can switch the linter to Pylint by following these instructions. It should be turned on by default if you have Pylint installed.
You can set the code formatter to use Black with these instructions.
The "Format on Save" option in settings will automatically run Black and fix your code for you every time you save it.
Setting up Pylint in PyCharm can be done with this Pylint extension.
Similarly, there's also an extension to format your code with Black. Follow the instructions here to set it up.
Turning off Black formatting¶
If you're using Black to format your code, you'll notice that sometimes it likes to reformat your lists, when we might want them formatted a different way. Say I'm using a length-9 list to represent a 3×3 data structure. I might format this list like this to hint at this behavior.
my_box = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, ]
With Black, however,
my_box gets turned into a long list, removing this nice
3×3 grid that we made.
# After formatting with Black my_box = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, ]
We can use a comment of
# fmt: off to turn off formatting temporarily,
# fmt: on to turn it back on. Black will ignore all code between
these two comments, leaving our precious
# fmt: off my_box = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, ] # fmt: on
Error messages are telling you something!¶
Similarly, error messages in Python are designed to tell you what your problem is and where it occurs in your code. Reading these messages, finding the spot in your code where the error is occurring, and sometimes even giving it a google can help you a lot. Python 3.11 will even point at where the error is located in a specific line of your code.
Say I create a function that takes in a list of names, and prints
for every person in the list, and save it in a Python file called hello.py.
1 2 3 4 5 6
The file prints the first three names fine, but then we get an error that shows up in the command line:
Hello, Cameron! Hello, Ben! Hello, Alyssa! Traceback (most recent call last): File "/Users/cmk/Documents/class/6.101/python_trix/example.py", line 6, in <module> say_hello(123) File "/Users/cmk/Documents/class/6.101/python_trix/example.py", line 2, in say_hello for person in people: TypeError: 'int' object is not iterable
What we see underneath the first three lines is called a stack trace, which
tells us on which lines of the code the error ocurred. In the stack trace above,
we can see the entire problem. I passed in
123 instead of a list of strings,
say_hello(people) function is trying to iterate over the
123 is an
int, not a
list that the code expects.
The last line in the stack trace tells us why the code stopped working, and it
confirms our suspicion: we can't iterate over an
int object, which is a
Variable Names and Comments¶
You should always use variable names that describe what data the variable holds.
Please don't use variables like
list. These don't
provide any context and make it harder for you, and LAs helping you, to
understand your own code.
Python also uses
snake_case by convention for variables and functions, as
UpperCamelCase for your
classes. Following these conventions will make your code easier to read by other
Python developers and LAs in 6.101.
1 2 3 4 5 6 7 8
1 2 3 4 5 6 7 8
Use comments to explain complicated parts of your code, but don't just rewrite what the a line of code is doing in a comment. Most of the time, you don't need that many comments in your code. Instead, you can usually rename some variables or refactor your code into appropriately-named helper functions. Then, someone with a good knowledge of Python can read your code and understand what it does without having to read any comments.
This concept is usually referred to as "self-documenting code", and this StackOverflow answer has a great example of how it's useful. Try to make your code in 6.101 self-documenting!
Below you can see an example of good comments versus bad comments. Consider this method for booking a ticket which modifies a global list of flights and increments a ticket counter. Some comments have been added that do not add any helpful information to someone reading the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
These comments just restate directly what the code is doing, without addressing
why the code works that way. Also, some less common elements such as the
else block of the for loop are left unexplained. Comments that address the
broader aspects of why your code works the way it does will be much more
helpful to anyone reviewing your code. See the example below for some improved
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
This example uses comments more effectively compared to the previous one by:
- adding a docstring that explains what the entire function does at a high level
- adding other high level comments inside the function that explain what specific chunks of the function do
- explaining what the more complicated pieces of the code do, such as the
elseblock of the for loop
In short, use comments to explain the higher level why of your code without just restating what the code does.
_ as a variable name¶
Sometimes we don't want to use a variable in a list comprehension or a for loop.
A common convention in Python is to assign this to a single underscore
variable name to indicate that that variable isn't used.
If we want to call a function 10 times, we could discard the iterator variable like so:
for _ in range(10): do_thing()
It's less common, but you can also do this in a list comprehension! Say we want
to make a list of 10 random numbers. We don't need the iterator, so we can
assign it to
_ to show that we're not using it.
values = [random.random() for _ in range(10)]
While it might seem at first glance that Pylint and Black are similar tools, they actually do different things! Pylint is a linter, which helps you spot errors and bad patterns in your code, while Black is a formatter, which automatically restructures your code into a common format to make it easier to read and consistent with style. ↩