Introduction
In 61A, each project has a composition score, worth 3 points, that is graded on the style of your code. This document provides some guidelines.
After your code works, you should strive to do the following things:
- Make your code easier to read
- Make your code concise
- Make your code efficient (optional for this class)
Sometimes these goals conflict with each other, and sometimes there are exceptions to the rules. Whatever you do, you should always try to make your code easy to read — use your judgement.
Some of these guidelines have one or more of the following marks:
- N: a "non-essential" guideline; these guidelines are not necessary for this class, but are generally good practice
- P: a Python-specific guideline; these are "Pythonic" style conventions that don't necessarily apply to other languages
Finally, here is a link to to PEP-8, the official Python style guide.
Names and variables
Meaningful names
Variable and function names should be self-descriptive:
a, b, m = 100, 0, 0
thing = 'hello world'
stuff = lambda x: x % 2
goal, score, opp_score = 100, 0, 0
greeting = 'hello world'
is_even = lambda x: x % 2
Indices and mathematical symbols
Using one-letter names and abbreviations is okay for indices, mathematical symbols, or if it is obvious what the variables are referring to.
i = 0 # a counter for a loop
x, y = 0, 0 # x and y coordinates
p, q = 5, 17 # mathematical names in the context of the question
In general, i
, j
, and k
are the most common indices used.
'o' and 'l'
Do not use the letters 'o' and 'l' by themselves as names:
o = O + 4 # letter 'O' or number 0?
l = l + 5 # letter 'l' or number 1?
Unnecessary variables
Don't create unnecessary variables. For example,
result = answer(argument)
return result
return answer(argument)
However, if it is unclear what your code is referring to, or if the expression is too long, you should create a variable:
do_something(lambda x: x % 49 == 0, (total + 1) // 7)
divisible_49 = lambda x: x % 49 == 0
score = (total + 1) // 7
do_somethig(divisible_49, score)
Profanity
Don't leave profanity in your code. Even if you're really frustrated.
eff_this_class = 666
Naming convention:
NP: Uselower_case_and_underscores
for variables and functions:
TotalScore = 0
finalScore = 1
def Mean_Strategy(score, opp):
...
total_score = 0
final_score = 1
def mean_strategy(score, opp):
...
On the other hand, use CamelCase
for classes:
class example_class:
...
class ExampleClass:
...
Spacing and Indentation
Whitespace style might seem superfluous, but using whitespace in certain places (and omitting it in others) will often make it easier to read code. In addition, since Python code depends on whitespace (e.g. indentation), it requires some extra attention.
Spaces vs. tabs
Use spaces, not tabs for indentation. Our starter code always uses 4
spaces instead of tabs. If you use both spaces and tabs, Python will
raise an IndentationError
.
Indent size
P: Use 4 spaces to denote an indent. Technically, Python allows you to use any number of spaces as long as you are consistent across an indentation level. The conventional style is to use 4 spaces.Line Length
Keep lines under 80 characters long. Other conventions use 70 or 72 characters, but 80 is usually the upper limit.
Double-spacing
Don't double-space code. That is, do not insert a blank line in between lines of code. Personally, I find that harder to read.
Spaces with operators
N: Use spaces between+
and -
. Depending on how illegible
expressions get, you can use your own judgement for *
, /
, and **
(as long as it's easy to read at a glance, it's fine).
x=a+b*c*(a**2)/c-4
x = a + b*c*(a**2) / c - 4
Spacing lists
N: When using tuples, lists, or function operands, leave one space after each comma,
:
tup = (x,x/2,x/3,x/4)
tup = (x, x/2, x/3, x/4)
Line wrapping
NP: If a line gets too long, you have two options. If you are using parentheses or braces with multiple elements, you can continue them onto the next line:def func(a, b, c, d, e, f,
g, h, i):
# body
tup = (1, 2, 3, 4, 5,
6, 7, 8)
names = ('alice',
'bob',
'eve')
Notice that the subsequent lines line up with the start of the
sequence. If the above rule does not apply, you can use Python's \
operator:
total = this_is(a, very, lengthy) + line + of_code \
+ so_it - should(be, separated) \
+ onto(multiple, lines)
Where you put the \
in relation to binary operators (e.g.
hi \ + bye
versus hi + \ bye
) will vary from person to person
— for our class, it doesn't matter.
Blank lines
NP: Leave a blank line between the end of a function or class and the next line:def example():
return 'stuff'
x = example() # notice the space above
Trailing whitespace
N: Don't leave whitespace at the end of a line.Repetition
In general, don't repeat yourself (DRY). It wastes space and can be computationally inefficient.
Complex expressions
Do not repeat complex expressions:
if a + b - 3 * h / 2 % 47 == 4:
total += a + b - 3 * h / 2 % 47
return total
Instead, store the expression in a variable:
turn_score = a + b - 3 * h / 2 % 47
if turn_score == 4:
total += turn_score
return total
This will also make your code more readable.
Computation-heavy function calls
Don't repeat computationally-heavy function calls:
if takes_one_minute_to_run(x) != ():
first = takes_one_minute_to_run(x)[0]
second = takes_one_minute_to_run(x)[1]
third = takes_one_minute_to_run(x)[2]
Instead, store the expression in a variable:
result = takes_one_minute_to_run(x)
if result != ():
first = result[0]
second = result[1]
third = result[2]
if/else conditions
DON'T have the same code in both the if
and the else
clause of a
conditional:
if pred: # bad!
print('stuff')
x += 1
return x
else:
x += 1
return x
Instead, pull the line(s) out of the conditional:
if pred: # good!
print('stuff')
x += 1
return x
Comments
Recall that Python comments begin with the #
sign. Keep in mind that
the triple-quotes are technically strings, not comments. Comments can
be helpful for explaining ambiguous code, but there are some
guidelines for when to use them.
Docstrings
P: Put docstrings only at the top of functions. Docstrings are denoted by triple-quotes at the beginning of a function or class:def average(fn, samples):
"""Calls a 0-argument function SAMPLES times, and takes
the average of the outcome.
"""
You should not put docstrings in the middle of the function — only put them at the beginning.
Remove commented-out code
Remove commented-out code from final version. You can comment lines
out when you are debugging. When you are turning in your project, take
all commented lines out (including TODO
s) — this makes it easier
for readers to read your code.
Unnecessary comments
Don't write unnecessary comments. For example, the following is bad:
def example(y):
x += 1 # increments x by 1
return square(x) # returns the square of x
Your actual code should be self-documenting — try to make it as obvious as possible what you are doing without resorting to comments. Only use comments if something is not obvious or needs to be explicitly emphasized
Control Structures
Boolean comparisons
Don't compare a boolean variable to True
or False
:
if pred == True: # bad!
...
if pred == False: # bad!
...
Instead, do this:
if pred: # good!
...
if not pred: # good!
...
Redundant if/else
Don't do this:
if pred: # bad!
return True
else:
return False
Instead, do this:
return pred # good!
Similar if/else suites
(related to the previous:) Don't do this:
if num != 49:
total += example(4, 5, True)
else:
total += example(4, 5, False)
In the example above, the only thing that changes between the conditionals is the boolean at the end. Instead, do this:
total += example(4, 5, num != 49)
while vs. if
Don't use a while
loop when you should use an if
:
while pred:
x += 1
return x
Instead, use an if
if pred:
x += 1
return x
Parentheses
P: Don't use parentheses with conditional statements:if (x == 4):
...
elif (x == 5):
...
while (x < 10):
...
Parentheses are not necessary in Python conditionals (they are in other languages though).
Miscellaneous
Semicolons
P: Do not use semicolons. This is not C/C++/Java/etc.Checking None
P: Use is
and is not
for None
, not ==
and !=
.
Implicit False
P: Use the "implicit" False
value when possible. Examples include
empty containers like []
, ()
, {}
, set()
.
if lst: # if lst is not empty
...
if not tup: # if tup is empty
...
Generator expressions
P: Generator expressions are okay for simple expressions. This includes list comprehensions, dictionary comprehensions, set comprehensions, etc. Generator expressions are neat ways to concisely create lists. Simple ones are fine:ex = [x*x for x in range(10)]
L = [pair[0] + pair[1]
for pair in pairs
if len(pair) == 2]
However, complex generator expressions are very hard to read, even illegible. As such, do not use generator expressions for complex expressions.
L = [x + y + z for x in nums if x > 10 for y in nums2 for z in nums3 if y > z]
Use your best judgement.