This repository contains Jupyter notebooks with coding exercises and their solutions, inspired by and adapted from Reuven M. Lerner's "Python Workout: 50 ten-minute exercises". Below is a summary of the exercises and key skills demonstrated.
📝 Note for Readers : This is a quick-reference guide. Some examples are simplified for clarity. In production code, always add proper error handling, type hints, and edge case validation.
http://pgbovine.net
Skill
Description
Example
User Input
Get user input using input()
user_guess = input('Guess a number: ')
Integer Conversion
Convert string to integer
int(user_input)
Random Generation
Generate random integer
random.randint(0, 100)
Input Validation
Validate numeric input
user_input.isdigit()
String Replacement
String replacement operation
input_str.replace('.', '')
Variable Arguments
Accept variable number of arguments
def my_sum(*numbers):
Sum Initialization
Sum with initial value
sum([1,2,3], start=0)
Error Handling
Exception handling mechanism
try: ... except ValueError: (⚠️ catch specific exceptions)
Float Conversion
Float conversion and calculation
float(run_time)
Walrus Operator
Walrus operator (:=)
while (run_time := input(...)):
String Reversal
Reverse string order
''.join(reversed(s)) or s[::-1]
Index-Value Pairs
Get index-value pairs
enumerate(reversed(...))
ASCII Conversion
Character ASCII value conversion
ord(char.upper())
Digital Check
Check if digit
digit.isdigit()
Built-in Conversion
Built-in base conversion function
int('1A', 16)
Skill
Description
Example
String Slicing
Extract substring with indexes
word[1:]
String Formatting
Format strings with f-strings
f'{word}way'
String Splitting
Split string into list
sentence.split()
String Joining
Join list into string
' '.join(word_list)
Character Rotation
ROT13 encryption implementation
chr((ord(c.upper()) - 65 + 13) % 26 + 65) or codecs.encode(word, 'rot13')
Case Conversion
Convert to lowercase
word.lower()
String Sorting
Sort characters in string
sorted('python')
Case-insensitive Sort
Sort with key function
sorted(s, key=str.lower)
Skill
Description
Example
Sequence Slicing
Get first/last elements
seq[:1] + seq[-1:]
List Memory Allocation
Dynamic memory management
Lists grow dynamically; append() is amortized O(1)
Tuple Efficiency
Fixed-size, immutable
Tuples are faster for read-only data; use for immutable sequences
Container Checking
Check if container is empty
if not items:
Dictionary Merging
Combine dictionaries
{**d1, **d2}
Type Checking
Verify data type
isinstance(item, dict)
Advanced Sorting
Multi-key sorting
sorted(data, key=lambda x: (x[1], x[0]))
Itemgetter Usage
Extract specific elements
operator.itemgetter(1, 0)
Formatted Output
Control string width/precision
f'{last:12s}{first:10s}{grade:.1f}'
Set Operations
Get unique elements
set('independence')
Element Counting
Count occurrences
word.count(letter)
Counter Usage
Efficient frequency counting
Counter('independence').most_common(1)
Skill
Description
Example
Safe Key Access
Get values without KeyError
my_dict.get(key, default_value) returns None if unspecified
Default Dictionaries
Automatic key initialization
defaultdict(list) or defaultdict(int) auto-creates keys
Dictionary Views
Iterate key-value pairs
for k, v in my_dict.items():
Set Uniqueness
Remove duplicate elements
unique = set([1,2,2,3])
Key Collection
Get all dictionary keys
my_dict.keys()
Set Operations
Mathematical set operations (|&^-)
dict1.keys() | dict2.keys() (union)
Skill
Description
Example
File Opening
Open files with different modes
open(filename, 'r')
Context Management
Automatic file closing
with open(...) as f:
CSV Processing
Read/write CSV files
csv.reader(f, delimiter=':')
JSON Handling
Parse and load JSON data
json.load(json_file)
Batch Processing
Process multiple files
os.listdir(dirname)
Path Manipulation
Combine file paths safely
os.path.join(dirname, filename)
File Format Detection
Check file extensions
filename.endswith('.json')
Memory Optimization
Read files line by line
f.readline() with walrus operator
Pretty Printing
Format complex structures
pprint.pprint(data, sort_dicts=False)
Delimiter Handling
Work with different separators
csv_writer = csv.writer(f, delimiter='\t')
Newline Control
Manage line endings
newline='' in open()
Data Serialization
Convert objects to JSON
json.dump(data, file)
File Type Filtering
Select specific file types
glob.glob('*.json')
Skill
Description
Example
Default Parameters
Set default parameter values
def func(name='World')
Variable Scope
LEGB rule (Local, Enclosed, Global, Built-in)
global, nonlocal keywords
Keyword Arguments
Accept arbitrary keyword arguments
def func(**kwargs)
Function Dictionary
Store functions in dictionary
ops = {'+': operator.add}
Operator Module
Use built-in operator functions
import operator; operator.add(2,3)
Lambda Functions
Anonymous functions for short operations
lambda a, b: a + b
Closure Functions
Remember enclosing scope
def outer(): def inner(): ...; return inner
Function Factories
Generate functions dynamically
def factory(): return lambda x: x*2
Returning Functions
Return a function from another function
return password_gen
Arbitrary Arguments
Accept variable number of arguments
def my_sum(*numbers):
Dynamic Attribute Handling
Accept and use arbitrary keyword arguments
def myxml(tag, content='', **kwargs): ...
Skill
Description
Example
Type Validation
Validate numeric input types
if not isinstance(amount, (int, float)): raise ValueError('amount')
Decimal Arithmetic
Precise monetary calculations
from decimal import Decimal; Decimal('0.2')
Package Structure
Create package with __init__.py and modules
import tax.income_tax
Import Path
Temporarily extend module search path
import sys; sys.path.append('./data')
Skill
Description
Example
Class & self
Initialize instance attributes
def __init__(self, flavor): self.flavor = flavor
Instance vs Class
Access class attribute from instances
class Bowl: max_scoops = 3
str /repr
Custom printable/representation of objects
def __repr__(self): return f'Bowl(scoops={self.scoops})'
Inheritance & Override
Subclass and override attributes/methods
class ExtraBowl(Bowl): max_scoops = 5
super() initializer
Call parent constructor to avoid duplication
super().__init__(color, 4)
Class name lookup
Get class name of instance
self.__class__.__name__
f-string !r
Use repr formatting for clarity
f"{self.color!r}"
Subclass built-ins
Extend dict behavior safely
class StrDict(dict): ...
Dunder method override
Intercept item set/get
def __setitem__(self, k, v): ...
Nested comprehensions
Query across nested containers
[a for ex in zoo.exhibits for a in ex.animals]
Aggregation
Compute totals across objects
sum(a.leg_num for ex in zoo.exhibits for a in ex.animals)
Iterator & Generator Skills
Skill
Description
Example
Iterator Protocol
Implement __iter__ and __next__; raise StopIteration to end
class MyEnumerate: def __iter__(self): return self; def __next__(self): ...
Separate Iterator Class
Return a fresh iterator each time to avoid shared state
class CycleList: def __iter__(self): return CycleIterator(data, n)
Cycling with Modulo
Loop over data repeatedly using modular index
value = data[i % len(data)]
Generator Function
Use yield to lazily produce values
def word_generator(f, n): ... yield word
Early Termination
Stop a generator with return when a limit is reached
if count >= n: return
Generator Expression
Inline lazy sequence construction
(int(d) for d in str(num) if d.isnumeric())
Stateful Infinite Generator
Preserve state between yields for ongoing values
def elapsed_time_gen(): yield now - last
Comprehension & Generator Skills
Skill
Description
Example
List Comprehension
Generate lists with expressions
[abs(x) for x in numbers]
Nested List Comprehension
Flatten 2D lists
[sub for row in data for sub in row]
Dict Comprehension
Generate dicts from iterables
{k: v for k, v in pairs}
Set Comprehension
Generate sets from iterables
{x for x in data}
Conditional Comprehension
Add if condition in comprehension
[x for x in data if x > 0]
Filter Function
Filter elements with a function
filter(str.isdigit, data)
Map Function
Apply function to all elements
map(abs, numbers)
Generator Expression
Lazy evaluation of sequences
(x*x for x in range(10))
File Processing with Comprehension
Process file lines/words
' '.join([pl_word(w) for l in f for w in l.split()])
Dict/Set Flip
Flip dict keys and values
{v: k for k, v in d.items()}
Appendix A - Additional Skills
Skill
Description
Example
Combinations (itertools)
List all 2-combinations; useful for pair checks
from itertools import combinations; list(combinations(data, 2))
Counter.most_common
Get most frequent element efficiently
Counter(data).most_common(1)[0] returns (element, count) tuple
Set subtraction
Find missing numbers from 1..n via set difference
set(range(1, len(data)+2)) - set(data) for missing in [1..n+1]
Stack via list/subclass
Use list methods or subclass list for stack ops
stack = []; stack.append(x); stack.pop()
Bracket validation (stack)
Validate parentheses/brackets using push/pop
stack and b == stack.pop()
Move zeroes to end
Shift all zeroes to the list's end
for _ in range(data.count(0)): data.remove(0); data.append(0)
Common prefix (zip)
Use zip to align chars; stop at first mismatch
"".join(c[0] for c in zip(*strs) if len(set(c)) == 1)
Reverse integer digits
Reverse digits with slicing and preserve sign
int(str(abs(x))[::-1]) * (1 if x >= 0 else -1)
Reverse 8-bit binary
Format to 8 bits, reverse, parse base 2
int(f'{n:08b}'[::-1], 2)
Roman numerals to int
Sum symbols plus subtractive pairs
sum(roman[c] for c in s) + sum(v for k, v in special.items() if k in s)
Each exercise includes a video tutorial for additional learning:
The exercises focus on practical Python programming skills and include interactive elements for hands-on learning. Each exercise builds upon fundamental concepts while introducing new Python features and best practices.
🔍 Additional Review Comments
Missing Topics (Consider Adding):
Type Hints - Modern Python best practice: def func(x: int) -> str:
Decorators - Essential for real-world Python: @property, @staticmethod, custom decorators
Context Managers - Custom __enter__/__exit__ for resource management
Dataclasses - Simplify class definitions: @dataclass
asyncio - Asynchronous programming basics
Testing - pytest, unittest, doctest
Logging - Better than print: import logging
Regular Expressions - re module for pattern matching
Pathlib - Modern path handling: Path instead of os.path
Virtual Environments - venv, pip, requirements.txt
Use PEP 8 naming conventions consistently
Add docstrings to all functions/classes
Prefer explicit over implicit (e.g., return None explicitly)
Use f-strings over % or .format() (already covered ✓)
Follow "ask for forgiveness" (try/except) vs "look before you leap" (if checks) where appropriate
List comprehensions > for loops (already covered ✓)
Use set for membership testing: if x in my_set: is O(1)
Generator expressions for large datasets (already covered ✓)
collections.Counter for counting (already covered ✓)
bisect module for sorted lists
functools.lru_cache for memoization