book website: https://effectivepython.com/
!python --version
Python 3.10.4
import sys
print(sys.version_info)
print(sys.version)
sys.version_info(major=3, minor=10, micro=4, releaselevel='final', serial=0) 3.10.4 (main, Jul 7 2022, 20:56:54) [Clang 13.1.6 (clang-1316.0.21.2.5)]
bytes and str¶bytes contains sequences of 8-bit values, and str contains sequences of Unicode code points.bytes and str instances can’t be used together with operators (like >, ==, +, and %).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
print(repr(to_str(b'foo')))
print(repr(to_str('bar')))
'foo' 'bar'
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
print(repr(to_bytes(b'foo')))
print(repr(to_bytes('bar')))
b'foo' b'bar'
!python -c 'import locale; print(locale.getpreferredencoding())'
UTF-8
str.format¶places = 3
number = 1.23456
print(f'My number is {number:.{places}f}')
My number is 1.235
if/else expression provides a more readable alternative to using the Boolean operators or and and in expressions.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': ['']}
red = my_values.get('red', [''])[0] or 0
red
'5'
def get_first_int(values, key, default=0):
found = values.get(key, [''])
if found[0]:
return int(found[0])
return default
print(get_first_int(my_values, 'red'))
print(get_first_int(my_values, 'blue'))
print(get_first_int(my_values, 'green'))
print(get_first_int(my_values, 'yellow'))
5 0 0 0
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
enumerate Over range¶enumerate provides concise syntax for looping over an iterator and getting the index of each item from the iterator as you go.enumerate instead of looping over a range and indexing into a sequence.enumerate to specify the number from which to begin counting (zero is the default).”zip to Process Iterators in Parallel¶zip built-in function can be used to iterate over multiple iterators in parallel.zip creates a lazy generator that produces tuples, so it can be used on infinitely long inputs.zip truncates its output silently to the shortest iterator if you supply it with iterators of different lengths.zip_longest function from the itertools built-in module if you want to use zip on iterators of unequal lengths without truncation.names = ['Cecilia', 'Lise', 'Marie']
counts = [len(n) for n in names]
longest_name = None
max_count = 0
for name, count in zip(names, counts):
if count > max_count:
longest_name = name
max_count = count
print(longest_name)
print(max_count)
Cecilia 7
names.append('Rosalind')
for name, count in zip(names, counts):
print(name)
Cecilia Lise Marie
import itertools
for name, count in itertools.zip_longest(names, counts):
print(f'{name}: {count}')
for name, count in itertools.zip_longest(names, counts, fillvalue=0):
print(f'{name}: {count}')
Cecilia: 7 Lise: 4 Marie: 5 Rosalind: None Cecilia: 7 Lise: 4 Marie: 5 Rosalind: 0
else Blocks After for and while Loops¶else blocks to immediately follow for and while loop interior blocks.else block after a loop runs only if the loop body did not encounter a break statement.else blocks after loops because their behavior isn’t intuitive and can be confusing.a = 4
b = 9
for i in range(2, min(a, b) + 1):
print('Testing', i)
if a % i == 0 and b % i == 0:
print('Not coprime')
break
else:
print('Coprime')
Testing 2 Testing 3 Testing 4 Coprime
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
assert coprime(4, 9)
assert not coprime(3, 6)
def coprime_alternate(a, b):
is_coprime = True
for i in range(2, min(a, b) + 1):
if a % i == 0 and b % i == 0:
is_coprime = False
break
return is_coprime
assert coprime_alternate(4, 9)
assert not coprime_alternate(3, 6)
fresh_fruit = {
'apple': 10,
'banana': 8,
'lemon': 5,
}
def make_lemonade(count):
pass
def out_of_stock():
pass
def slice_bananas(count):
pass
def make_cider(count):
pass
def make_smoothies(pieces):
pass
if count := fresh_fruit.get('lemon', 0):
make_lemonade(count)
else:
out_of_stock()
if (count := fresh_fruit.get('banana', 0)) >= 2:
pieces = slice_bananas(count)
to_enjoy = make_smoothies(pieces)
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'
key Parameter¶dict Insertion Ordering¶get Over in and KeyError to Handle Missing Dictionary Keys¶defaultdict Over setdefault to Handle Missing Items in Internal State¶__missing__¶None¶None and Docstrings to Specify Dynamic Default Arguments¶functools.wraps¶map and filter¶yield from¶send¶throw¶itertools for Working with Iterators and Generators¶@classmethod Polymorphism to Construct Objects Generically¶super¶collections.abc for Custom Container Types¶@property Instead of Refactoring Attributes¶@property Methods¶__getattr__, __getattribute__, and __setattr__ for Lazy Attributes¶__init_subclass__¶__init_subclass__¶__set_name__¶subprocess to Manage Child Processes¶ThreadPoolExecuter When Threads Are Necessary for Concurrency¶asyncio¶asyncio¶asyncio Event Loop to Maximize Responsiveness¶concurrent.futures for True Parallelism¶try/except/else/finally¶contextlib and with Statements for Reusable try/finally Behavior¶datetime Instead of time for Local Clocks¶pickle Reliable with copyreg¶decimal When Precision Is Paramount¶deque for Producer-Consumer Queues¶bisect¶heapq for Priority Queues¶memoryview and bytearray for Zero-Copy Interactions with bytes¶repr Strings for Debugging Output¶pdb¶tracemalloc to Understand Memory Usage and Leaks¶warnings to Refactor and Migrate Usage¶typing to Obviate Bugs¶