EECS 183 Python Style Guide
Following consistent code style guidelines…
- … helps other people read and understand your code
- … helps you make fewer mistakes
- … is important when more than one person is working on a project
The code style in this course will be graded against the following guidelines, which are a simplified version of the official PEP 8(opens in new tab) style guide used by professional Python developers.
There’s a lot here, but don’t worry; soon, it will all just be normal and easy for you. If a guideline mentions a programming concept we haven’t covered in class yet (for example, the mention of “class names”), then just ignore it for now.
Flake8 Will Help a Lot
Flake8 is one of the extensions we set up when installing VS Code. This extension will be very helpful for notifying you of many (but not all!) style mistakes, so pay attention to the yellow and red squiggles it adds to your code! You can hover over them with your mouse to see what it’s complaining about. For example:

As another example, with this code:
def say_hi() -> None:
print("Hello world!")
if __name__ == "__main__":
say_hi()we get:

Note in the image above the many indications of a single problem:
- In the
Explorerarea in the upper-left,hello.pyis written in red text and has a red1indicating one problem. - There is a red squiggle at the problem area in the text editor pane. If you hover your mouse pointer over such indications, a pop-up will describe the problem.
- The area on the far right depicts a tiny view of your entire file (which of course contains very little code in this case). But note the red horizontal line indicating a problem, and also the red vertical line in the scroll bar itself.
- If you choose the
Terminalmenu, thenNew Terminal, and then click theProblemstab, you can see a list of problems, as shown at the bottom of the image above. This can be helpful when you have a few problems that you can’t find in a large file. You can click on a listed problem, and it will take your cursor directly to the location of the problem.
It’s important to note that, while Flake8 is a wonderful tool, it will not perfectly capture every issue we’re looking for in this style guide, so be on the lookout. But it will make this work much, much easier.
Managing Line Lengths
We will enforce an 80 character limit per line of code. This includes comments and lines of code. Python is a little picky about how to break up long lines, so we’ll consider this matter of style in more depth than any other.
Flake8 will give helpful warnings about this as well. We’ve also already configured VS Code so that a thin vertical line appears at the 80 character limit in your editor window.
For example:

Note above the Flake8 message when hovering over the word “what”, which is right at the limit. Also note the vertical line in the editor window itself, depicting the limit.
How should we fix an issue like this? We’ll consider that next.
Long Expressions
To break up long expressions onto multiple lines, let’s first look at an example:
Bad Style:
def main() -> None:
...
# Long mathematical expression - line is too long
total_result = first_variable**2 + second_variable**3 - (third_variable / 4) + fourth_variable_from_a_function()
...Good Style:
def main() -> None:
...
# Long mathematical expression - split across lines nicely
total_result = (
first_variable**2
+ second_variable**3
- (third_variable / 4)
+ fourth_variable_from_a_function()
)
...To put this process into words: If you have a long mathematical or logical expression, first wrap the whole thing in an extra set of parentheses ( ) to clearly mark the start and end of the expression. Then have the first line end with (, and a final line containing ) by itself. The final ) should be lined up vertically with the start of the entire statement (e.g., the first “t” of “total” above). The items that are between the ( ) should be placed one line at a time, indented one extra level. Also note that each new line inside the ( ) starts with an operator (e.g., + or -). The end result is that the overall format of the expression can be seen at a glance.
Here’s another example, this time with a long condition. The same principles apply.
Good Style:
def main() -> None:
...
# Long 'if' statement
if (
condition_one
and (condition_two or condition_three)
and condition_four
and not condition_five
):
do_something()
...Consider the example below. At least the lines are broken up! But the operator placement is not according to best style. Each line should begin, not end, with an operator.
Bad Style:
def main() -> None:
...
# Long mathematical expression
total_result = (
first_variable**2 +
second_variable**3 -
(third_variable / 4) +
fourth_variable_from_a_function()
)Long Print Statements
Consider a print statement with a long string inside. The string can be broken into multiple strings, one per line, within the print parentheses. Placing adjacent string literals next to each other with no comma between them causes Python to join them automatically – this is called implicit string concatenation.
The following print is too long and should be broken up.
Bad Style:
print(f"Homework contribution (with free bonus points): {homework_contribution} points")Below is an example in which that long string is broken up using implicit string concatenation.
Good Style:
print(
"Homework contribution (with free bonus points): "
f"{homework_contribution} points"
)For the good style version immediately above, note:
- The
printoutput will be exactly the same as the originalprint. - There’s one (smaller) string per line, with no comma between them – they are joined automatically by Python.
- The first string ends with a space (inside the quotes) since we want a space after the
:. - Only the second string needs to be an f-string, so we intentionally did not make the first string an f-string.
Long Data Structures
Follow a similar pattern for lists, tuples, sets, and dictionaries. For example, here’s a long list split across multiple lines:
Good Style:
my_long_list = [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
]For a dictionary, it’s best to have one key: value pair per line:
Good Style:
my_complex_dict = {
"key_one": "this is a very, very, very, very long value",
"key_two": "another long value",
}Tip: Adding a trailing comma on the last item (like 24, or "another long value",) is a common and recommended practice. It makes it cleaner to add new items later and results in cleaner changes in documents from one version to another. This isn’t required, though.
Function Calls & Definitions
For function calls and definitions, break the line after the opening parenthesis, indent the items inside (one per line), and left-align the close parenthesis.
For example, for the my_function function call:
Good Style:
def other() -> None:
my_function(
parameter_one="this is very long",
parameter_two=another_variable,
parameter_three=True,
)A function with a long parameter list is handled similarly:
Good Style:
def my_function(
parameter_one: str,
parameter_two: int,
parameter_three: bool,
) -> None:
print("hello")In the rest of this document, we consider other components of good style.
Whitespace and Indentation
Space Around Operators
There must be a single space around operators (=, +=, ==, +, -, *, /, etc.) and after commas.
Bad Style:
count+=(a+b)*c/d+some_function()
my_list = [1,2,3]Good Style:
count += (a + b) * c / d + some_function()
my_list = [1, 2, 3]However, note the exception in making a function call with keyword arguments.
Spaces and Parentheses
There should not be a space immediately inside parentheses.
Bad Style:
pluralize( "person" ,"people" , number_of_people )There should not be a space between a function name and the parentheses.
Bad Style:
pluralize ("person" ,"people" , number_of_people)Good Style:
pluralize("person", "people", number_of_people)Line Break with :
There should be a line break after every colon (:) starting a new block.
Bad Style:
if x > 3: y = 2Good Style:
if x > 3:
y = 2End of the Line
There should not be any blank spaces at the end of any line. Flake8 will warn you about this.
4-Space Indentation
Indent your code using 4 spaces for each new block. (Note that Python also syntactically requires proper indentation.)
Correct indentation is required for a Python program to even run, but there are a few indentation practices that are only style errors and not syntax errors.
Bad Style:
def main() -> None:
x = 3
if x > 0:
print("x is positive.")
elif x == 0:
print("x is zero.") # Too little indentation
else:
for i in range(3):
print("*") # Too much indentation
return 0Good Style:
def main() -> None:
x = 3
if x > 0:
print("x is positive.")
elif x == 0:
print("x is zero.")
else:
for i in range(3):
print("*")
return 0Four Spaces vs. Tab
As long as you use VS Code for all your programming, hitting the tab OR hitting space four times should be fine and equivalent, due to the default settings of VS Code.
You should know, though, that in some text editors, the two approaches are represented differently, even if they have the same appearance. And unfortunately, Python will get confused and complain about syntax errors if you have a mix of the two in your program. So stick with programming in VS Code (not editing your code in a different program or text editor) to make sure you don’t run into problems with this.
If you end up with a tabs verses spaces problem in your code, open your file in VS Code, highlight all the text, and choose View, Command Palette… (or press Cmd+Shift+P on Mac / Ctrl+Shift+P on Windows). In the box that appears, type “Convert Indentation to Spaces” and press Enter. This will automatically fix all indentation in your file to use spaces, resolving any mixing errors.
Blank Lines
Use blank lines to separate logical sections of your code and improve readability.
- Use two blank lines before and after a function definition (
def) or a class definition (class). - Use one blank line to separate logical “paragraphs” inside a function.
Bad Style:
def function_one() -> None:
"""
RME...
"""
# ... code ...
def function_two() -> None:
"""
RME...
"""
# Get user input
name = input("Enter name: ")
age = int(input("Enter age: "))
# Process the input
print(f"Hello, {name}. You are {age}.")Good Style:
def function_one() -> None:
"""
RME...
"""
# ... code ...
def function_two() -> None:
"""
RME...
"""
# Get user input
name = input("Enter name: ")
age = int(input("Enter age: "))
# Process the input
print(f"Hello, {name}. You are {age}.")Blank lines should have no whitespace in them. Problems with this are not always visible to us, but Flake8 will point it out:

Variables and Constants
Descriptive Names
Variables must have names that describe their purpose. i, j, and k used as loop counters are acceptable.
Bad Style:
var1 = 0
var2 = 0Good Style:
num_students = 0
num_classes = 0Naming Conventions
Use standard Python naming conventions:
- Variables and functions must be “snake_case” (all lowercase with underscores separating words).
course_credits = 4def calculate_gpa():
- Constants (variables that never change) must be in “ALL_CAPS”.
MAX_CREDITS = 18
- Class names must be “PascalCase” (first letter of each word capitalized).
class CityBus:- You can ignore this requirement until we talk about classes much later in the semester.
No Global Variables
Do not use global variables (variables defined outside of any function). It may not seem like a big deal when you’re first learning how to program, but global variables make code harder to understand, debug, and maintain. However, global constants are acceptable, defined at the top of the file.
Unlike other programming languages, there’s no way in Python to force a constant to have only one value. That is, it’s possible in Python to assign a constant a different value during program execution. But this should definitely not be done. If a value needs to change, the item should be a variable (and named accordingly), not a constant.
No Magic Numbers
Magic numbers are numbers that do not have an immediately obvious meaning. They should be stored in constants. 0, 1, and 2 are rarely considered magic numbers. Give every other number a descriptive name via a constant.
Bad Style:
area = 3.141592 * radius * radiusGood Style:
PI = 3.141592
area = PI * radius * radiusConditionals
Testing bool Expressions
Test bool expressions directly.
Bad Style:
# is_valid is a bool
if is_valid == True:
print("Valid!")Good Style:
# is_valid is a bool
if is_valid:
print("Valid!")Else and Elif
Use else (and elif) when appropriate.
Bad Style:
# is_valid is a bool
if is_valid:
print("Valid!")
if not is_valid:
print("Not valid!")Good Style:
# is_valid is a bool
if is_valid:
print("Valid!")
else:
print("Not valid!")Simplify if/else
In functions returning bool, simplify if/else expressions.
Bad Style:
def are_tied(score1: int, score2: int) -> bool:
if score1 == score2:
return True
else:
return FalseGood Style:
def are_tied(score1: int, score2: int) -> bool:
return score1 == score2Loops
Iteration Variables
Whenever you need temporary variables for iteration, use i, then j, then k. If the loop is more complex, use descriptive names.
Good Style:
for i in range(10):
# do something simple
for column in range(number_of_columns):
for row in range(number_of_rows):
# do something with (row, column)Functions
RMEs (Docstrings) for Functions
Except when specifically told otherwise, every function in your code must have an RME docstring ("""...""") immediately after the def line. The format of an RME comment will be described in lecture.
The one exception is that we will not require a formal RME docstring for any nested functions (functions defined inside other functions), as discussed when we study Pandas.
Limit Function Length
Very long functions should be broken into smaller, helper functions. Try to limit your functions to 50 lines of code. This does not apply to main in your first project.
Spacing for Keyword Arguments
Ordinarily we would expect a single space on the left and right of any =:
Good Style:
def main():
x = 5The one exception is when using keyword arguments in a function call. For example:
Bad Style:
def some_math(big: int, small: int, div: int = 1) -> float:
return (big - small) / div
def main():
some_math(small = 2, big = 6, div = 2)Good Style:
def some_math(big: int, small: int, div: int = 1) -> float:
return (big - small) / div
def main():
some_math(small=2, big=6, div=2)Note above, however, that the assignment of a default value (for example, that div defaults to 1) still has spaces around the =. It is only in the function call using keyword arguments that the spaces are omitted.
Program Structure
Import Statements
All import statements must be at the top of the file, just after the module docstring (file header), before any global constants, with a blank line before and after. Only import packages that you need for the program.
Good Style:
"""
my_code.py
...
"""
import numpy as np
import pandas as pd
MAX_USERS = 100
# ... rest of the code (functions, etc.) ...Global Code
All “runnable” code (code that isn’t a constant definition, function definition, or class definition) must be placed inside a main() function. This main() function should then be called at the end of your file inside a special block. This makes your code more organized, especially as it gets more complex.
Bad Style:
def print_greeting(name: str) -> None:
print(f"Hello, {name}!")
# The code below should be in a main function
my_name = "Natalie"
print_greeting(my_name)Bad Style:
def print_greeting(name: str) -> None:
print(f"Hello, {name}!")
if __name__ == "__main__":
# Better, but put in a main instead, and call main here
my_name = "Natalie"
print_greeting(my_name)Good Style:
def print_greeting(name: str) -> None:
print(f"Hello, {name}!")
def main() -> None:
# This code runs when the program starts
my_name = "Natalie"
print_greeting(my_name)
# This special "if" block must be at the end of your file.
# It tells Python to run the main() function when needed.
if __name__ == "__main__":
main()Ending Code Execution
Python contains a sys.exit() function to end your program. Do not call this function in any EECS 183 code. Your program must always exit naturally by reaching the end of your main function.
Type Annotations
Always use type annotations for every parameter and return type, except for a couple special cases for classes, described further below. We do not require type annotations in any other context.
Annotations for Functions
Consider the following good example:
Good Style:
def times_two(x: int) -> int:
return x*2Note in the example above:
- There is a single space after the
:in the parameter list (but not the:ending the line). - There is a single space before and after the
->. - Both the type of the parameter and the return type are specified.
If a function does not return anything, we must specify None as the return type. For example:
Good Style:
def greet(name: str) -> None:
print(f"Hi, {name}!")Annotations for Classes
Type annotations are similar for classes, with two exceptions:
- We do not annotate the type for the
selfparameter. - We do not specify a return type, nor
None, for__init__.
For example:
Good Style:
class Player:
def __init__(self, name: str, score: int):
self.name = name
self.score = score
def update_score(self, points: int) -> None:
self.score += pointsAdvice from Course Staff
All of us on staff are happy to answer your specific questions about code style. In fairness to all students, we will not provide a complete review of your code’s style or make any promises about a style grade prior to final submission of your work.
Copyright and Intellectual Property Notice
© 2026 Steven Bogaerts and William Arthur. All rights reserved.
All materials provided for this course, including but not limited to labs, projects, notes, and starter code, are the copyrighted intellectual property of the author(s).
- Student Use: These materials are provided solely for the educational use of students currently enrolled in this course at the University of Michigan - Ann Arbor. Students may not copy, reproduce, republish, or distribute these materials (in part or in full) to any public or private platform.
- External and Instructor Use: No part of these materials may be used, adapted, or distributed by external instructors or institutions without the explicit written permission of the author(s).
To request permission to use or adapt these materials for educational purposes, please contact the author(s).
Comments
The Top Comment (The Docstring)
At the top of each file, include a module docstring (
"""...""") with your (and your partner’s, if applicable) name, your (and your partner’s, if applicable) uniqname, and a small description of the program or file. This is included in all the starter code.Space After
#Always put a space after the
#symbol.Bad Style:
Good Style:
Comments for Clarity Only
Add a comment when the code would not be clear to you if you were reading it for the first time.
For example, the comment below is not necessary, because the code is quite simple on its own (once you know the basics of Python).
Bad Style:
In the next example, the purpose of the code is not immediately obvious, so the comment is very helpful.
Good Style:
Each comment should be a useful English note (like the comment above), not a recitation of the code. For example, the comments below are not helpful:
Bad Style:
Delete comments when they no longer serve their purpose. A classic example is the
TO DOtype of comments we sometimes leave for you in starter code. In the example below, theTO DOshould be deleted once the task is finished.Bad Style:
You may also find it useful to occasionally write notes to yourself in code. If they’re temporary notes that no longer serve a purpose, they should be deleted as well. The example below is one such situation.
Bad Style:
Comments on their Own Lines
Comments must be on their own lines, preceding the code they describe.
Bad Style:
The code above shows an inline comment. It can be appropriate when used sparingly, but to keep things simple for this course, we’ll ask you to just not use it. Use the style below instead.
Good Style:
Large Commented-Out Regions
You may find it useful at times to write some temporary code to check things while you’re working…
… and later you might not need it for a while, so you comment it out:
But for the final submission of your code, you should remove all such code entirely:
Good Style: