Writing better Python code
Image by https://www.pexels.com/@mikhail-nilov/ |
When we write code in any programming language, we tend to look into how code is written in the language. There are some guidelines and conventions that can help us to write better code and more readable code. There is even a term created for this in Python and it is Pythonic.
In this blog, I share some of my points of view on writing better Python code.
1. Wildcards Imports
Sometimes, when we look at a function and we do not know where it is imported from. For example
# bad practice to import all from math import * print(ceil(0.6))
This one is obvious however it is not when there are many imports and many lines of code in a file. A better way is
# good practice to import what we need from math import ceil print(ceil(0.6))
2. Unnecessary use of True and False
This is not particular to writing code in Python as we have seen this in other programming languages too.
names = ["ann", "beth", "candy", "debbie", "elaine", "faith", "geta"] def abc_names(name): if name[0:1] == "a" or name[0:1] == "b" or name[0:1] == "c": return True return False
The function can be just
def abc_names(name): return name[0:1] == "a" or name[0:1] == "b" or name[0:1] == "c"
or can be
def abc_name(name): return name[0:1] in ["a", "b", "c"]
3. Unnecessary traversal of the entire list
This is also not particular to writing code in Python.
cars = [ {"brand": "tesla", "owned": True}, {"brand": "honda", "owned": False}, {"brand": "toyota", "owned": True}, {"brand": "bmw", "owned": False}, ] # materialized the entire list, just to get the first item # this is bad practice when the list is huge. def first_owned(): return list(filter(lambda car: car["owned"], cars))[0] print(first_owned())
this can be better written as
def first_owned(): return next(filter(lambda car: car["owned"], cars), None)
where we get the next value from the filter generator and do not generate all the values. It is undesirable to do a list on the filter generator in this case.
4. Usage of generator
Among other things, Python makes it easy to create generators. We can avoid for loop entirely.
cars = [ {"brand": "tesla", "owned": True}, {"brand": "honda", "owned": False}, {"brand": "toyota", "owned": True}, {"brand": "bmw", "owned": False}, ] for i in range(len(cars)): if cars[i]["owned"]: print(cars[i]["brand"]) # simpler version for car in cars: if car["owned"]: print(car["brand"])
these can be easily written as
# use filter generator for car in filter(lambda car: car["owned"], cars): print(car["brand"])
5. Usage of comprehension list
Another cool thing about Python is the comprehension list.
cars = [ {"brand": "tesla", "owned": True}, {"brand": "honda", "owned": False}, {"brand": "toyota", "owned": True}, {"brand": "bmw", "owned": False}, ] brands = [] for car in cars: brands.append(car["brand"]) print(brands)
can be written as
print([car["brand"] for car in cars])
and we can even do filtering
# car that I owned print([car["brand"] for car in cars if car["owned])
6. zip function
The zip function is extremely useful to reference multiple lists. An example
cars = ["tesla", "honda", "toyota", "bmw"] owneds = [True, False, True, False] for i in range(len(cars)): if owneds[i]: print(cars[i])
can be written as
for car, owned in zip(cars, owneds): if owned: print(car)
7. Usage of decorator
Yet another cool feature is the decorator. There are many tutorials on Python's decorator online. Here is an example.
import timeit def fibonacci(n): if n == 0: return 0 if n == 1: return 1 return fibonacci(n - 2) + fibonacci(n - 1) start = timeit.default_timer() for i in range(40): print(fibonacci(i)) stop = timeit.default_timer() execution_time = stop - start print(execution_time)
This prints the Fibonacci sequence. The execution time is 66 seconds on my laptop. Let's keep the fibonacci function unchanged and add a decorator to have dynamic programming.
import timeit memo = [0, 1] def memoize(func): def inner(n): if n < len(memo): return memo[n] val = func(n) memo.append(val) return val return inner @memoize def fibonacci(n): if n == 0: return 0 if n == 1: return 1 return fibonacci(n - 2) + fibonacci(n - 1) start = timeit.default_timer() for i in range(40): print(fibonacci(i)) stop = timeit.default_timer() execution_time = stop - start print(execution_time)
Now, the execution time is 0.000149 seconds.
Conclusion
Python language offers a lot of nice features and let's use them to write better code.
Comments
Post a Comment