Pythonic Thinking
1. Know the version of your Python
import sys
print(sys.version_info)
print(sys.version)
2. Follow the PEP 8 Style Guide
- Within a file, function and classes should be seperated by 2 blank lines
- In a class, methods should be seperated by 1 blank line
- For type annotations, ensure that there is no separation between the variable name and the colon, and use a space before the type information
import numpy as np
def element_wise_add(data1: np.ndarray, data: np.ndarray) -> np.ndarray:
return data1 + data
- Protected instance attributes should be in _leading_underscore format
- Private instance attributes should be in __double_leading_underscore format
- Module-level constraints should be in ALL_CAPS format
- Instance methods in classes should use self, which refers to the object, as the name of the first parameter
- Don’t check for empty containers or sequences by comparing the length to zero (if len(somelist) == 0). Use if not somelist and assume that empty values will implicitly evaluate to False
- Always put import statements at the top of a file
- Always use absolute names when importing them, not names relative to the current module’s own path. (from bar import foo, not just from . import foo)
3. Know the difference between bytes and str
- Instances of bytes contain raw, unsigned 8-bit values (often in ASCII encoding)
- Instances of str contain Unicode code points that represent textual characters from human language
- To convert Unicode data to binary data, you must call encode method, and to convert binary to Unicode, you must call the decode method
# Takes a str or bytes and always returns a str
def to_str(bytes_or_str):
if isinstance(bytes_or_str, bytes):
value = bytes_or_str.decode('utf-8')
else:
value = bytes_or_str
return value
# Takes a str or bytes and always returns a byte
def to_byte(bytes_or_str):
if isinstance(bytes_or_str,str):
value = bytes_or_str.encode('utf-8')
else:
value = bytes_or_str
return value
- Write and read a file with (‘wb’,’rb’) if the file is written in binary mode (bytes)
pantry = [("Avocados", 1), ("Bananas", 2), ("Cherries", 15)]
for i, (item, count) in enumerate(pantry):
print(f'#{i+1} : {item.title():<10s} = {round(count)}')
places, number = 3, 1.23456
print(f'My number is approximately {number:.{places}f}')
- F-strings are succinct yet powerful because they allow for arbitrary Python expressions to be directly embedded within format specifiers
5. Write Helper Functions Instead of Complex Expressions
- Empty string, the empty list, and zero all evaluate to False implicitly
example = {'red' : ['5'], 'blue': ['0'], 'green': ['']}
red = int(example.get('red', [''])[0] or 0)
# empty string is evaluated as false
green = int(example.get('green', [''])[0] or 0)
# non-existent key leads to the list with empty string
white = int(example.get('white', [''])[0] or 0)
# written with ternary expression
red = example.get('red', [''])
red_str = int(red[0]) if red[0] else 0
# written with helper function
def get_first_int(values, key, default = 0):
found = values.get(key, [''])
if found[0]:
return int(found[0])
return default
- Always prefer a more readable code over a concise one
6. Prefer Multiple Assignment Unpacking over Indexing
- When indexing a tuple, objects are immutable whereas unpacking makes them mutable objects
- Swapping indexes within a line is possible!
def bubble_sort(a):
for _ in range(len(a)):
for i in range(1,len(a)):
if a[i] < a[i-1]:
a[i-1], a[i] = a[i], a[i-1]
- The right side of the assignment is always evaluated first, and its values are put into a new temporary unnamed tuple.
- Then, the unpacking pattern from the left side of the assignment a[i-1], a[i] is used to receive that unnamed tuple value and assign.
- Finally, the unnamed tuple silently goes away…
7. Prefer enumerate over Range
- Enumerate wraps any iterator with a lazy generator and yields pairs of the loop index and next value from the given iterator.
- The second parameter of enumerate controls where to begin the count (default=0)
flavors = ['vanilla', 'chocolate', 'raspberry', 'oreo']
for i, flavor in enumerate(flavors, 1):
print(f'{i+1} : {flavor}')
8. Use zip to Precess Iterators in Parallel
- term
- definition