Code discussions¶
I’ll expand this page as I find more examples in the exercise solutions you have sent in.
Antipatterns¶
An antipattern is a snippet of code that is often seen “in the wild” but has much cleaner and more readable alternatives.
if true return true¶
The result of a comparison is already a bool value True
or False
.
Instead of:
def is_right_angled_triangle(a, b, c):
if a**2 + b**2 == c**2:
return True
else:
return False
you can just write:
def is_right_angled_triangle(a, b, c):
return a**2 + b**2 == c**2
string construction by addition¶
Instead of printing numerical variables like this:
l = 5
w = 88
h = [3,8,4,1]
print('X=' + str(l) + ' Y=' + str(w) + ' Z=' + str(h))
make use of f-strings:
print(f'X={l} Y={w} Z={h}')
loop over index¶
In python it is very unusual to iterate over a list in this way:
xs = [3, 7, 1, -5, 88]
for i in range(len(xs)):
# now i only used for: ... xs[i] ...
print(xs[i])
For-loops can directly access each element in turn:
xs = [3, 7, 1, -5, 88]
for x in xs:
# can replace all uses of xs[i] with x
# ... x ...
print(x)
If both the index and the element is needed, make use of the enumerate()
function:
xs = [3, 7, 1, -5, 88]
for i, x in enumerate(xs):
print(x)
# can also use i for something other than xs[i]
print(i)
Efficiency¶
Generally speaking, any optimizations should be considered only when performance actually is a problem. Until then, readability and maintainability of the code is much more important.
Nested loops with conditions¶
We had an example where three positive numbers \(a<b<c\) could have any value, as long as they add to 1000. Some solutions used a triple-nested loop in this way:
for a in range(1, 1000):
for b in range(1, 1000):
for c in range(1, 1000):
if a + b + c == 1000 and a < b < c:
# ... do something here ...
It works fine, but runs quite slowly, since most of the a-b-c combinations fail the if-test.
An easy way to improve this is to make sure the sum condition \(a+b+c=1000\) always is true. This happens when \(c=1000-a-b\).
We still need to check the ordering \(a<b<c\), but already with this simple step, we’ve reduced the number of loops we run by a factor of 1000:
for a in range(1, 1000):
for b in range(1, 1000):
c = 1000 - a - b
if a < b < c:
# ... do something here ...
Of course, there are further improvements we could make now, for example it is not too hard to see that \(a\) must always be smaller than 333. But the gain in performance that we can get here is “only” another factor of 3.
Compared to how much thinking we have to do ourselves now, it is probably not worth it to spend more time on eliminating the \(a<b<c\) test. Remember that with every change we make, the program gets harder to understand and more corner cases need to be checked that they still work correctly.