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 two things:
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 will have one or more of the following marks:
Finally, here is a link to to PEP-8, the official Python style guide.
# bad -- don't do this! a, b, m = 100, 0, 0 thing = 'hello world' stuff = lambda x: x % 2 # good goal, score, opp_score = 100, 0, 0 greeting = 'hello world' is_even = lambda x: x % 2
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.
# bad! o = O + 4 # letter 'O' or number 0? l = l + 5 # letter 'l' or number 1?
# bad! result = answer(argument) return result # good! 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:
# bad! do_something(lambda x: x % 49 == 0, (total + 1) // 7) # good! divisible_49 = lambda x: x % 49 == 0 score = (total + 1) // 7 do_somethig(divisible_49, result)
# bad! eff_this_class = 666
lower_case_and_underscores
for variables and
functions:
# bad! TotalScore = 0 finalScore = 1 def Mean_Strategy(score, opp): ... # good! total_score = 0 final_score = 1 def mean_strategy(score, opp): ...
CamelCase
for classes:
# bad! class example_class: ... # good! class ExampleClass: ...
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. For that reason, this section has quite a few guidelines that you should consider.
IndentationError
.+
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).
# bad! x=a+b*c*(a**2)/c-4 # good! x = a + b*c*(a**2) / c - 4
,
:
# bad! tup = (x,x/2,x/3,x/4) # good! tup = (x, x/2, x/3, x/4)
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.
def example(): return 'stuff' x = example() # notice the space above
In general, don't repeat yourself (DRY). It wastes space and can be computationally inefficient.
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.
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[0] third = result[0]
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
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.
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.
TODO
s) -- this
makes it easier for readers to read your code.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
True
or False
:
if pred == True: # bad! ... if pred == False: # bad! ...
Instead, do this:
if pred: # good! ... if not pred: # good! ...
if pred: # bad! return True else: return False
Instead, do this:
return pred # good!
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
loop when you should use an if
:
while pred: x += 1 return x
Instead, use an if
if pred: x += 1 return x
if (x == 4): ... elif (x == 5): ... while (x < 10): ...
Parentheses are not necessary in Python conditionals (they are in other languages though).
is
and is not
for None
, not ==
and !=
.False
value when possible. Examples
include empty containers like []
, ()
, {}
, set()
.
if lst: # if lst is not empty ... if not tup: # if tup is empty ...
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.