Effective Python (1): Pythonic Thinking
Item 1: Know Which Version of Python You're Using
- Two mayor versions of Python in active use: Python 2 and Python 3;
- Multiple popular runtime for Python: CPython, Jython, IronPython, PyPy, etc;
- Prefer Python3 because that is the primary focus of the Python community.
Item 2: Follow the PEP 8 Style Guide
- Always follow the PEP 8 style guide when writing python codes.
Item 3: Know the Differences Between bytes, str, and unicode
- In python 3, bytes contains sequences of 8-bit values, str contains sequences of Unicode characters. bytes and str instances can't be used together with operators (like > or +);
- In python 2, str contains sequences of 8-bit values, unicode contains sequences of Unicode characters. str and unicode instances can be used together with operators if the str only contains 7-bit ASCII characters;
- Use helper functions to ensure that the inputs you operate on are the type of character sequence you expect;
- - 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’).
The core of your program should use Unicode character types
- str in python 3
- unicode in python 2
Helper functions:
#! Python 3 # 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 bytes def to_bytes(bytes_or_str): if isinstance(bytes_or_str, str): value = bytes_or_str.encode('utf-8') else: value = bytes_or_str return value
#! Python 2 # Takes a str or unicode and always returns a unicode def to_unicode(unicode_or_str): if isinstance(unicode_or_str, str): value = unicode_or_str.decode('utf-8') else: value = unicode_or_str return value # Takes a str or unicode and always returns a str def to_str(unicode_or_str): if isinstance(unicode_or_str, unicode): value = unicode_or_str.encode('utf-8') else: value = unicode_or_str return value
Item 4: Write Helper Functions Instead of Complex Expressions
Pass
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 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
- Prefer using positive stride values in slices without start or end indexes. Avoid negative stride values if possible.
- Consider doing two assignments(one to slice, another to stride) or using islice from the itertools built-in module.
Item 7: Use List Comprehensions Instead of map and filter
- List comprehensions are clearer than the map and filter build-in functions because they don’t require extra lambda expressions.
- List comprehensions allow you to easily skip items from the input list, a behavior map doesn’t support without help from filter.
- Dictionaries and sets also support comprehension expressions.
Item 8: Avoid More Than Two Expressions in List Comprehensions
Pass
Item 9: Consider Generator Expressions for Large Comprehensions
Pass
Item 10: Prefer enumerate Over range
Code example
flavor_list = ['vanilla', 'chocolate', 'pecan', 'strawberry'] for i, flavor in enumerate(flavor_list, 1): print('%d: %s' % (i, flavor))
- enumerate provides concise syntax for looping over an iterator and getting the index of each item from the iterator as you go;
- You can supply a second parameter to enumerate to specify the number from which to begin counting (zero is the default).
Item 11: Use zip to Process Iterators in Parallel
- In python 3, zip is a lazy generator that produces tuples. While in python 2, zip returns the full result as a list of tuples;
- zip truncates its output silently if you supply it with iterators of different lengths.
Item 12: Avoid else Blocks After for and while Loops
- The else block after a loop only runs if the loop body did not encounter a break statement.
Item 13: Take Advantage of Each Block in try/except/else/finally
- The else block helps you minimize the amount of code in try blocks and visually distinguish the success case from the try/except blocks.
- An else block can be used to perform additional actions after a successful try block but before common cleanup in a finally block.