Separation of ConcernsΒΆ
FiltersΒΆ
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd = filter(lambda n: n % 2, numbers)
even = (number for number in numbers if not number % 2)
print(f"Sum of odd values: {sum(odd)}")
print(f"Sum of even values: {sum(even)}")
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd = 0
even = 0
for number in numbers:
if number % 2:
odd += number
else:
even += number
print(f"Sum of odd values: {odd}")
print(f"Sum of even values: {even}")
# With Filter
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd = filter(lambda n: n % 2, numbers)
even = (number for number in numbers if not number % 2)
print(f"Sum of odd values: {sum(odd)}")
print(f"Sum of even values: {sum(even)}")
# Naive Approach
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
odd = 0
even = 0
for number in numbers:
if number % 2:
odd += number
else:
even += number
print(f"Sum of odd values: {odd}")
print(f"Sum of even values: {even}")
AdaptersΒΆ
for first, item in loop_first([]):
if first:
edge_case(item)
continue
default(item)
is_first = True
for items in []:
if is_first:
edge_case(item)
is_first = False
continue
default(item)
# With Adapter
for first, item in loop_first([]):
if first:
edge_case(item)
continue
default(item)
# Naive Approach
is_first = True
for items in []:
if is_first:
edge_case(item)
is_first = False
continue
default(item)
π‘ learnt from:
Source: Will McGugan
Reference: Stealing Open Source code from Textual
from __future__ import annotations from typing import Iterable, TypeVar T = TypeVar("T") def loop_first(values: Iterable[T]) -> Iterable[tuple[bool, T]]: """Iterate and generate a tuple with a flag for first value.""" iter_values = iter(values) try: value = next(iter_values) except StopIteration: return yield True, value for value in iter_values: yield False, value
from __future__ import annotations from typing import Iterable, TypeVar T = TypeVar("T") def loop_last(values: Iterable[T]) -> Iterable[tuple[bool, T]]: """Iterate and generate a tuple with a flag for last value.""" iter_values = iter(values) try: previous_value = next(iter_values) except StopIteration: return for value in iter_values: yield False, previous_value previous_value = value yield True, previous_value
from __future__ import annotations from typing import Iterable, TypeVar T = TypeVar("T") def loop_first_last(values: Iterable[T]) -> Iterable[tuple[bool, bool, T]]: """Iterate and generate a tuple with a flag for first and last value.""" iter_values = iter(values) try: previous_value = next(iter_values) except StopIteration: return first = True for value in iter_values: yield first, False, previous_value first = False previous_value = value yield first, True, previous_value
Short-Circuit SearchΒΆ
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def find_number(numbers):
numbers = (n for n in numbers if (n % 3) == 0)
try:
number = next(numbers)
except StopIteration:
number = None
return number
number = find_number(numbers)
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def find_number(numbers):
for n in numbers:
# concerns are not seperated
if (n % 3) == 0:
return n
return None
number = find_number(numbers)
# With Generator Short Circuit
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def find_number(numbers):
numbers = (n for n in numbers if (n % 3) == 0)
try:
number = next(numbers)
except StopIteration:
number = None
return number
number = find_number(numbers)
# Naive Approach
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9]
def find_number(numbers):
for n in numbers:
# concerns are not seperated
if (n % 3) == 0:
return n
return None
number = find_number(numbers)
Generic SolutionΒΆ
from typing import Iterator, Any, Callable, TypeVar
T = TypeVar('T')
def find_first(
iterable: Iterator[T],
condition: Callable[[T], bool],
terminal: Any = None
) -> Any:
"""
Find the first item which meets a specific condition.
Args:
iterable:
which will be searched.
condition:
which needs to be meet by the item.
terminal:
value which will be returned if the condition did not return True
for any item in the iterable.
Returns:
The first item in the iterable for which the condition returns True.
If the condition does not return True for any item in the iterable, the
terminal value is returned.
Examples:
>>> numbers = [1, 2, 3, 4 ,5 ,6]
>>> value = find_first(numbers, condition=lambda _: True)
>>> value == 1
True
>>> numbers = [1, 2, 3, 4 ,5 ,6]
>>> value = find_first(numbers, condition=lambda item: item % 3 == 0)
>>> value == 3
True
>>> value = find_first(numbers, condition=lambda item: item % 7 == 0)
>>> value is None
True
>>> value = find_first(numbers, condition=lambda item: item % 7 == 0, terminal=7)
>>> value == 7
True
"""
items = (item for item in iterable if condition(item))
try:
item = next(items)
except StopIteration:
item = terminal
return item
Context ManagerΒΆ
Factor out context into a context manager.
import os
from contextlib import contextmanager
@contextmanager
def chdir(path):
old_dir = os.getcwd()
os.chdir(path)
yield path
os.chdir(old_dir)
def initialize(directory):
with chdir(directory) as _working_dir:
with open('some-file.txt', 'w') as f:
f.write("Some content")
from contextlib import chdir
def initialize(directory):
with chdir(directory) as _working_dir:
with open('some-file.txt', 'w') as f:
f.write("Some content")
import os
def initialize(directory):
old_dir = os.getcwd()
os.chdir(directory)
os.chdir(old_dir)
with open('some-file.txt', 'w') as f:
f.write("Some content")
os.chdir(old_dir)
# With Context Manager
import os
from contextlib import contextmanager
@contextmanager
def chdir(path):
old_dir = os.getcwd()
os.chdir(path)
yield path
os.chdir(old_dir)
def initialize(directory):
with chdir(directory) as _working_dir:
with open('some-file.txt', 'w') as f:
f.write("Some content")
# With Python 3.11
from contextlib import chdir
def initialize(directory):
with chdir(directory) as _working_dir:
with open('some-file.txt', 'w') as f:
f.write("Some content")
# Naive Approach
import os
def initialize(directory):
old_dir = os.getcwd()
os.chdir(directory)
os.chdir(old_dir)
with open('some-file.txt', 'w') as f:
f.write("Some content")
os.chdir(old_dir)
π‘ learnt from:
Source: Raymond Hettinger
Reference: Transform Python Slides
DecoratorΒΆ
Factor out unrelated repetitive work into a decorator.
import logging
from functools import wraps
def log_execution(f):
@wraps(f)
def wrapper(*args, **kwargs):
logging.debug(f"Entering: {f.__name__}")
result = f(*args, **kwargs)
logging.debug(f"Leaving: {f.__name__}")
return result
return wrapper
@log_execution
def some_function():
return "Some Result"
@log_execution
def other_function():
return "Other Result"
import logging
def some_function():
logging.debug("Entering: some_function")
result = "Some Result"
logging.debug("Leaving: some_function")
return result
def other_function():
logging.debug("Entering: other_function")
result = "Some Result"
logging.debug("Leaving: other_function")
return result
# With Decorator
import logging
from functools import wraps
def log_execution(f):
@wraps(f)
def wrapper(*args, **kwargs):
logging.debug(f"Entering: {f.__name__}")
result = f(*args, **kwargs)
logging.debug(f"Leaving: {f.__name__}")
return result
return wrapper
@log_execution
def some_function():
return "Some Result"
@log_execution
def other_function():
return "Other Result"
# Naive Approach
import logging
def some_function():
logging.debug("Entering: some_function")
result = "Some Result"
logging.debug("Leaving: some_function")
return result
def other_function():
logging.debug("Entering: other_function")
result = "Some Result"
logging.debug("Leaving: other_function")
return result