Python/Flask Coding Style
-
Avoid complexity in your code. If it's hard to understand what's going on in a function, break it out. It shouldn't take a lot of explaining to show what code is doing. Commenting will help with this.
-
Most Nerevu projects have a
manage.py
file that has CLI commands that can be run for a project using the following CLI call -manage {function_name}
. If the project you are working on has amanage.py
file with aprettify
function in it, you should runmanage prettify
on your code before your PR is merged. This keeps the formatting consistent. -
Practice
DRY
coding (Don't Repeat Yourself). If you find you are writing similar code over and over, try abstracting it out into a function (if it makes sense to do so). The below example is trivial, but should get the point across.
# INCORRECT
user1 = 'doug peterson'
user1 = " ".join(name.capitalize() for name in user1.split(" "))
user2 = 'george clooney'
user2 = " ".join(name.capitalize() for name in user2.split(" "))
# CORRECT
def format_name(name):
return " ".join(name.capitalize() for name in user1.split(" "))
user1 = 'doug peterson'
user1 = format_name(user1)
user2 = 'george clooney'
user2 = format_name(user2)
- Start thinking like a functional programmer. Don't mutate objects. Return new objects instead. See the docs for more info on functional programming in python.
users = [{"name": "brian"}, {"name": "jenna"}]
# INCORRECT
def lowercase_name(user):
user["name"] = user["name"].lower()
return user
list_of_users = map(lowercase_name, users)
# CORRECT
def lowercase_name(user):
return {**user, "name": user["name"].lower()}
list_of_users = map(lowercase_name, users)
- use
pos
instead ofi
when using enumerate (withrange()
you don't need to use this)
names = ['bob', 'jack', 'bill', 'jessica']
# INCORRECT
for i, name in enumerate(names):
print(f"{i}: {name}")
# CORRECT
for pos, name in enumerate(names):
print(f"{pos}: {name}")
- Generators
Name Generators gen_{function_name}
Use generators instead of appending to empty lists
# INCORRECT
letters = []
for i in range(10):
if i % 2:
letters.append(chr(i))
# CORRECT - notice the naming of the function as well as the (gen_)
def gen_letters(nums):
for i in nums:
if i % 2:
yield chr(i)
letters = list(gen_letters(range(10)))
- use list comprehensions instead of list and map
names = ['Phillip', 'Annette']
lowercase_names = lambda n: n.lower()
# INCORRECT
new_names = list(map(lowercase_names, names))
# CORRECT
new_names = [lowercase_names(n) for n in names]
- use
dict.items()
instead ofkey in dict
obj = {"name": "brian"}
# INCORRECT
for key in obj:
print(obj[key])
# CORRECT
for key, val in obj.items()
print(val)
- make variable names meaningful unless they are in a list comprehension or lambda function, etc..
users = [{"name": "brian"}, {"name": "jenna"}]
# INCORRECT
def gen_users(n):
yield n['name']
list_of_users = list(gen_users(users))
# CORRECT
def gen_users(user):
yield user['name']
list_of_users = list(gen_users(users))
# ALSO CORRECT
list_of_users = [u["name"] for u in users]
list_of_users = map(lambda u: u["name"], users)
- If you're not sure if a key will be present in a dictionary, use
dict.get("key")
so your code doesn't break.
user = {"name": "brian"}
# INCORRECT
age = user["age"] # Throws a KeyError
# CORRECT
age = user.get("age") # returns None
- Add breaks to short circuit for loops once the correct field is found
numbers = [1,2,3,4,5,6,7,8,9,10]
# CORRECT EXAMPLE
contains_number_four = False
for number in numbers:
if number is 4:
contains_number_four = True
break # prevent the loop from continuing!
- Nested loops in general are code smell really -
Set
datatypes are indexed, so doingif x in Set
is faster than doing a double for loop
names = ["Bob", "Jesse", "Alyssa", "Frank"]
whitelist = {"Bill", "Jack", "Frank", "Frank"}
# These functions yield names that are present in a whitelist
# INCORRECT
def gen_names():
for name in names:
for other_name in whitelist:
if name == other_name:
yield name
# CORRECT
def gen_names():
for name in names:
if name in whitelist:
yield name
# MORE CORRECT
def gen_names():
for name in set(names).intersection(whitelist):
yield name
- Don't use
types
(e.g. str, list, dict, etc.) in your variable names
# INCORRECT VARIABLE NAMES
numbers_array = [1,2,3,4,5,6,7,8,9,10]
user_dict = {'name': 'bob', 'age': 16}
names_str_list = ['bill', 'george', 'katie', 'geoffrey', 'jessica']
# CORRECT VARIABLE NAMES
numbers = [1,2,3,4,5,6,7,8,9,10]
user = {'name': 'bob', 'age': 16}
names = ['bill', 'george', 'katie', 'geoffrey', 'jessica']
- Don't commit commented out code.
name = 'bob'
# DON'T COMMIT THIS
# name += "cat"
# print(name)
- Most Nerevu projects have a
manage.py
file that has CLI commands that can be run for a project using the following CLI call -manage {function_name}
. If the project you are working on has amanage.py
file with aprettify
function in it, you should runmanage prettify
on your code before your PR is merged. This keeps the formatting consistent.