Use Python 3
python --version
import sys
print(sys.version_info)
print(sys.version)
- Use 4 [spaces]
- no more than 79 lines in
- nest line of long line should be 4 [spaces] indented
class
anddef
should be separated by 2 empty lines (top, bottom)- in
class
, methods should be separated by 1 empty line {key: value,}
no space before colonvar = something
spaces before and after colondef some(name: str):
no space before colon in type annotations
lowercase_underscore
for functions, variables and attributes_leading_underscore
for protected instance attributes__double_leading_underscore
for private instance attributesclass CapitalizedWord
ALL_CAPS
for module-level constantsdef some(self,):
for name of first parameter for instance methods in classesdef some(cls,)
for name of first parameter of a class method
Find the one, and/or only one obvious way to do it.
if a is not
if not some_list
to check if emptyif some_list
to check if not empty- no single-line
if
,for
,while
,except
.
- All
import
are always on the top from bar import foo
always use absolute namesfrom . import foo
for relative import- Section imports in the following order:
- standard library modules
- 3rd-party modules
- your own modules
Use Unicode sandwich, always decode string to "utf-8" as soon as possible. Always work with b'ytes'
and b'ytes'
or str
and str
, never b'ytes'
and str
.
Use helper functions to turn bytes to strings:
def to_str(bytes_or_str):
"""Turns bytes into string, or return string"""
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode("utf-8")
else:
value = bytes_or_str
return value
To turn string to bytes:
def to_bytes(bytes_or_str):
"""Turns str into bytes, or return bytes"""
if isinstance(bytes_or_str, str):
value = bytes_or_str.encode("utf-8")
else:
value = bytes_or_str
return value
Use "rb"
and "wb"
"%(do_not) use C-style string" % (formating)
"{do_not} use this one".format("too")
f_string = f'{Use} {this} format'
Perks:
- Can put Python expressions into braces:
pantry = [
('avocados', 1.25),
('bananas', 2.5),
('cherries', 15),
]
for i, (item, count) in enumerate(pantry):
f_string = f"#{i+1}: {item.title():<10s} = {round(count)}"
print(f_string)
>>>
#1: Avocados = 1
#2: Bananas = 2
#3: Cherries = 15
- Can split over multiple lines:
for i, (item, count) in enumerate(pantry):
print(f"#{i+1}: "
f"{item.title():<10s} = "
f"{round(count)}")
- Can put variables into braces:
places = 3
number = 1.23456
print(f"My number is {number:.{places}f}")
>>>
My number is 1.235
Use helper functions for some repetitive task, even if you need to repeat it only couple of times.
from urllib.parse import parse_qs
my_values = parse_qs('red=5&blue=0&green=',
keep_blank_values=True)
print(repr(my_values))
>>>
{'red': ['5'], 'blue': ['0'], 'green': ['']}
my_values = {'red': ['5'], 'blue': ['0'], 'green': ['']}
def get_first_int(values, key, default=0):
found = values.get(key, [""])
if found[0]:
return int(found[0])
return default
red = get_first_int(my_values, "red")
blue = get_first_int(my_values, "blue")
green = get_first_int(my_values, "green")
print(red, blue, green)
>>>
5 0 0
In Python tuple
type is a immutable, ordered sequence of values.
snack_calories = {
"chips": 140,
"popcorn": 80,
"nuts": 190,
}
items = tuple(snack_calories.items())
print(items)
>>>
(('chips', 140), ('popcorn', 80), ('nuts', 190))
- Unpacking:
item = ("Peanut butter", "Jelly")
first, second = item #Unpacking
print(f"{first} and {second}")
>>>
Peanut butter and Jelly
- Use unpacking to swap in single line:
def bubble_sort(a):
for _ in range(len(a)):
for i in range(1, len(a)):
if a[i] < a[i-1]:
print(a, a[i], a[i-1])
a[i-1], a[i] = a[i], a[i-1] # Swap
names = ["pretzels", "carrots", "arugula", "bacon"]
bubble_sort(names)
print(names)
>>>
['arugula', 'bacon', 'carrots', 'pretzels']
- Use unpacking with
for
andenumerate()
:
snacks = [("bacon", 350), ("donut", 240), ("muffin", 190)]
for rank, (name, calories) in enumerate(snacks, 1):
print(f"#{rank}: {name} has {calories} calories")
>>>
#1: bacon has 350 calories
#2: donut has 240 calories
#3: muffin has 190 calories
- You can
for
loop overrange()
of integers:
from random import randint
random_bits = 0
for i in range(32):
if randint(0, 1):
random_bits |= 1 << i
print(bin(random_bits))
>>>
0b11111001110001011111000011011111
- You can
for
loop over sequence directly:
flavor_list = ["vanilla", "chocolate", "pecan", "strawberry"]
for flavor in flavor_list:
print(f"{flavor} is delicious")
>>>
vanilla is delicious
chocolate is delicious
pecan is delicious
strawberry is delicious
- You can add index by using
range()
:
for i in range(len(flavor_list)):
flavor = flavor_list[i]
print(f"{i+i}: {flavor}")
>>>
1: vanilla
2: chocolate
3: pecan
4: strawberry
- But, it is better to use
enumerate()
:
for i, flavor in enumerate(flavor_list, 1):
print(f"{i}: {flavor}")
>>>
1: vanilla
2: chocolate
3: pecan
4: strawberry
- You can use list comprehensions to derive a list:
names = ["Cecilia", "Lise", "Marie"]
counts = [len(n) for n in names]
print(counts)
>>>
[7, 4, 5]
- You can iterate over both lists in parallel:
longest_name = None
max_count = 0
for i in range(len(names)):
count = counts[i]
if count > max_count:
longest_name = names[i]
max_count = count
print(longest_name)
>>>
Cecilia
- Use
zip()
for two or more iterators:
for name, count in zip(names, counts):
if count > max_count:
longest_name = name
max_count = count
print(longest_name)
>>>
Cecilia
- However, it will iterate over shortest input. There is
itertools.zip_longest()
to iterate over longest list:
import itertools
names.append("Rosalind")
for name, count in itertools.zip_longest(names, counts):
print(f"{name}, {count}")
>>>
Cecilia, 7
Lise, 4
Marie, 5
Rosalind, None
You can, but shouldn't put else
after for
loop:
for i in range(3):
print("Loop", i)
else:
print("Else Block!")
>>>
Loop 0
Loop 1
Loop 2
Else Block!
else
behaves differently in for
and while
loops compared to if/else
statements. In for
and while
loops else
will always run after loop is ended.
- Helper function to find coprimes:
def coprime(a, b):
for i in range(2, min(a, b) + 1):
if a % i == 0 and b % i == 0:
return False
return True
print(coprime(4, 9), coprime(3, 6))
>>>
True False
- Another one:
def coprime_alternative(a, b):
is_coprime = True
for i in range(2, min(a, b) + 1):
if a % i == 0 and b % i == 0:
print(a, b, a%i,b%i)
is_coprime = False
break
return is_coprime
print(coprime_alternative(4, 9), coprime_alternative(3, 6))
>>>
True False
Use new (Python 3.8) walrus operator - :=
:
fresh_fruit = {
"apple": 10,
"banana": 8,
"lemon": 5,
}
class OutOfBananas(Exception):
pass
def make_lemonade(count):
pass
def make_cider(count):
pass
def slice_bananas(count):
pass
def make_smoothies(count):
pass
def out_of_stock():
pass
if count := fresh_fruit.get("lemon", 0):
make_lemonade(count)
else:
out_of_stock()
if (count := fresh_fruit.get("apple", 0)) >= 4:
make_cider(count)
else:
out_of_stock()
if (count := fresh_fruit.get("banana", 0) >= 2):
pieces = slice_bananas(count)
else:
pieces = 0
try:
smoothies = make_smoothies(pieces)
except OutOfBananas:
out_of_stock()
- Use
:=
in cases when switch/case statement is needed:
if (count := fresh_fruit.get("banana", 0)) >= 2:
pieces = slice_bananas(count)
to_enjoy = make_smoothies(count)
elif (count := fresh_fruit.get("apple", 0)) >= 4:
to_enjoy = make_cider(count)
elif count := fresh_fruit.get("lemon", 0):
to_enjoy = make_lemonade(count)
else:
to_enjoy = "Nothing"
- Use
:=
in case you need do/while loop construct:
def pick_fruit():
pass
def make_juice(fruit, count):
pass
bottles = []
while fresh_fruit := pick_fruit():
for fruit, count in fresh_fruit.items():
batch = make_juice(fruit, count)
bottles.extend(batch)