Forward
The book is really effective, that is you read a small chunk of the book to get a really interesting ideas to write a better python code (Example: item 9 Consider Generator Expressions for Large Comprehensions), Pythonic ways to code most common patterns (Example: item 10 Prefer enumerate
Over range
and item 11 Use zip
to Process Iterators in Parallel) and also advice for good practices (Example: item 1: Follow the PEP 8 Style Guide).
What I really liked in the book is the author putting a lot of attention on writing readable, reusable and maintainable code, thinking a lot about newbies who will read your code and also about adding functionalities to to your code while preserving backward compatibility.
Content
Chapter 1: Pythonic Thinking
Item 1: Know Which Version of Python You’re Using
There are two ways to inspect python interpreter version:
1. type python -v
2. use os.sys.version
Item 2: Follow the PEP 8 Style Guide
The PEP 8 contains guidelines about code formatting
Item 3: Know the Differences Between bytes, str, and unicode
In python 3: str is a sequence of unicode characters and bytes is a sequence of bytes
In python 2: unicode is a sequence of unicode characters and str is a sequence of bytes
Use helper functions (isinstance
) to ensure that the inputs you operate on are the type of character sequence you expect (8-bit values, UTF-8 encoded characters, Unicode characters, etc.).
If you want to read or write binary data to/from a file, always open the file using a binary mode (like 'rb' or 'wb').
Item 4: Write Helper Functions Instead of Complex Expressions
Python expressiveness let you define complex expressions, thought for the sake of code readability and maintanbility prefer defining helper functions instead.
Item 5: Know How to Slice Sequences
Avoid being verbose: Don’t supply 0 for the start index or the length of the sequence for the end index.
Slicing is forgiving of start or end indexes that are out of bounds, making it easy to express slices on the front or back boundaries of a sequence (like a[:20] or a[-20:]).
Assigning to a list slice will replace that range in the original sequence with what’s referenced even if their lengths are different.
Item 6: Avoid Using start, end, and stride in a Single Slice
If it's the case use separate instruction for slicing from start to end and for stride Example
l = l[::2]
l = l[1:9]
Item 7: Use List Comprehensions Instead of map and filter
For the sake of readability
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Prefer this
squares = [x ** 2 for x in a]
# Than this
squares = map(lambda x: x ** 2, a)
Item 8: Avoid More Than Two Expressions in List Comprehensions
For the sake of readability
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Prefer this
filtered = []
for row in matrix:
if sum(row) >= 10
for x in row:
if x % 3 == 0:
filtered.append(x)
# Than this
filtered = [x for row in matrix if sum(row) >= 10
for x in row if x % 3 == 0]
Item 9: Consider Generator Expressions for Large Comprehensions
Generator expressions avoid memory issues by producing outputs one at a time as an iterator.
Generator expressions can be composed by passing the iterator from one generator expression into the for subexpression of another.
Replacing the brackets []
with parenthesis ()
if for comprehensions will result in a generator
Item 10: Prefer enumerate Over range
Sometimes you want to loop over a sequence by index, python provide a utility method for that called enumerate
for idx, item in enumerate(list):
print(‘%d: %s’ % (i, item))
Item 11: Use zip to Process Iterators in Parallel
Python provides a utility method called zip
to process iterators in parallel
for name, count in zip(names, letters):
print('%s: %s' % (name, count))
Item 12: Avoid else Blocks After for and while Loops
Python supports else
block in for
and while
but it's counterintuitive and can be confusing, you should avoid it as much as you can.
Item 13: Take Advantage of Each Block in try/except/else/finally
handle = open(path, ‘r+’)
try:
data = handle.read()
op = json.loads(data)
value = (
op[‘numerator’] /
op[‘denominator’])
except ZeroDivisionError as e
return
else:
op[‘result’] = value
result = json.dumps(op)
handle.seek(0)
handle.write(result)
return value
finally:
handle.close()
The else
block helps you minimize the amount of code in try blocks and visually distinguish the success case from the try/except blocks.