In 61A, each project has a composition score, worth 2 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:
: a "non-essential" guideline; these guidelines are not necessary for this class, but are generally good practice
: 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
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
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?
Don't create unnecessary variables. For example,
result = answer(argument) return result
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_something(divisible_49, score)
Don't leave profanity in your code. Even if you're really frustrated.
eff_this_class = 666
lower_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
: 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.
Keep lines under 80 characters long. Other conventions use 70 or 72 characters, but 80 is usually the upper limit.
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
-. Depending on how illegible expressions get, you can use your own judgement for
**(as long as it's easy to read at a glance, it's fine).
x = a + b*c*(a**2) / c - 4
tup = (x,x/2,x/3,x/4)
tup = (x, x/2, x/3, x/4)
: 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):
tup = (1, 2, 3, 4, 5,
6, 7, 8)
names = ('alice',
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
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.
: Leave a blank line between the end of a function or class and
the next line:
x = example() # notice the space above
In general, don't repeat yourself (DRY). It wastes space and can be computationally inefficient.
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) second = takes_one_minute_to_run(x) third = takes_one_minute_to_run(x)
Instead, store the expression in a variable:
result = takes_one_minute_to_run(x) if result != (): first = result second = result third = result
DON'T have the same code in both the
if and the
else clause of a
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
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.
: 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
TODOs) -- this makes it easier
for readers to read your code.
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.
Don't compare a boolean variable to
if pred == True: # bad! ... if pred == False: # bad! ...
Instead, do this:
if pred: # good! ... if not pred: # good! ...
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
while pred: x += 1 return x
Instead, use an
if pred: x += 1 return x
: 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).
: Do not use semicolons. This is not C/C++/Java/etc.
is not for
: Use the "implicit"
False value when possible. Examples include
empty containers like
if lst: # if lst is not empty
if not tup: # if tup is empty
: 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 + pair
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.