Python Programming Labs

Master modern Python: unit testing, data classes, and type hints for production-ready code.

Modern Python Best Practices - Module 7

Write clean, testable, and maintainable Python code like a professional.

Lab 19: Unit Testing with unittest
Expert
Coding Challenge
Your Task: Learn to write unit tests using Python's built-in unittest module to ensure your code works correctly.

Detailed Requirements:
1. Create a test class:
import unittest class TestCalculator(unittest.TestCase): def test_add(self): self.assertEqual(add(2, 3), 5) def test_subtract(self): self.assertEqual(subtract(5, 3), 2)

2. Common assertion methods:
self.assertEqual(a, b) # a == b self.assertNotEqual(a, b) # a != b self.assertTrue(x) # x is True self.assertFalse(x) # x is False self.assertIsNone(x) # x is None self.assertIn(a, b) # a in b self.assertRaises(Error, func) # func raises Error

3. Setup and teardown:
class TestDatabase(unittest.TestCase): def setUp(self): # Runs before each test self.db = Database() def tearDown(self): # Runs after each test self.db.close() def test_insert(self): self.db.insert("data") self.assertEqual(len(self.db), 1)

4. Run tests:
# At the end of your file: if __name__ == '__main__': unittest.main() # Or from command line: # python -m unittest test_file.py

💡 Pro Tips:
• Test names must start with test_
• One assertion per test is ideal
• Test edge cases and error conditions
• Use pytest for more features

Expected Output:
... ---------------------------------------------------------------------- Ran 3 tests in 0.001s OK

Requirements Checklist

Import unittest module
Create a test class inheriting from unittest.TestCase
Write test methods starting with test_
Use assertEqual or other assertions
Add setUp or tearDown method
Include unittest.main() to run tests
Output
# Click "Run Code" to execute your tests
Hints & Tips
• Import: import unittest
• Class: class TestX(unittest.TestCase):
• Test method: def test_something(self):
• Assert: self.assertEqual(actual, expected)
• Run: if __name__ == '__main__': unittest.main()
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 20: Data Classes
Expert
Coding Challenge
Your Task: Learn to use @dataclass decorator for cleaner, more concise class definitions with automatic method generation.

Detailed Requirements:
1. Basic dataclass:
from dataclasses import dataclass @dataclass class Person: name: str age: int email: str = "" # Default value # Automatically gets __init__, __repr__, __eq__ p = Person("Alice", 30) print(p) # Person(name='Alice', age=30, email='')

2. Comparison and immutability:
@dataclass(order=True) # Enables <, >, <=, >= class Product: name: str price: float # For immutable (hashable) objects: @dataclass(frozen=True) class Point: x: float y: float

3. Field options:
from dataclasses import dataclass, field @dataclass class ShoppingCart: items: list = field(default_factory=list) # Mutable default owner: str = "Guest" def total(self): return sum(item.price for item in self.items)

4. Post-init processing:
@dataclass class Rectangle: width: float height: float area: float = field(init=False) # Not in __init__ def __post_init__(self): self.area = self.width * self.height

💡 Pro Tips:
• Use field(default_factory=list) for mutable defaults
• frozen=True makes instances immutable and hashable
• __post_init__ runs after generated __init__
• Dataclasses reduce boilerplate significantly

Expected Output:
Person(name='Alice', age=30, email='alice@email.com') Rectangle(width=5, height=3, area=15)

Requirements Checklist

Import dataclass from dataclasses
Use @dataclass decorator
Define class attributes with type hints
Add default values to fields
Create instances of the dataclass
Print or use the dataclass objects
Output
# Click "Run Code" to execute your Python code
Hints & Tips
• Import: from dataclasses import dataclass, field
• Decorator: @dataclass above class
• Type hints: name: str, age: int
• Default: email: str = ""
• Mutable: items: list = field(default_factory=list)
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 21: Type Hints & Annotations
Expert
Coding Challenge
Your Task: Learn to use type hints for better code documentation, IDE support, and static analysis with tools like mypy.

Detailed Requirements:
1. Basic type hints:
def greet(name: str) -> str: return f"Hello, {name}!" def add(a: int, b: int) -> int: return a + b age: int = 25 name: str = "Alice" is_active: bool = True

2. Collection types:
from typing import List, Dict, Tuple, Set, Optional def process_names(names: List[str]) -> List[str]: return [name.upper() for name in names] def get_user(id: int) -> Dict[str, any]: return {"id": id, "name": "Alice"} coordinates: Tuple[float, float] = (3.5, 4.2) unique_ids: Set[int] = {1, 2, 3}

3. Optional and Union types:
from typing import Optional, Union def find_user(id: int) -> Optional[str]: # Returns str or None return "Alice" if id == 1 else None def process(value: Union[int, str]) -> str: # Accepts int or str return str(value)

4. Type aliases and Callable:
from typing import Callable, TypeAlias # Type alias UserId: TypeAlias = int UserDict: TypeAlias = Dict[str, any] # Function type def apply(func: Callable[[int], int], value: int) -> int: return func(value)

💡 Pro Tips:
• Type hints don't enforce types at runtime
• Use mypy for static type checking
• Python 3.10+: use int | str instead of Union[int, str]
• Type hints improve IDE autocompletion

Expected Output:
Hello, Alice! Sum: 15 Names: ['ALICE', 'BOB'] User: Alice (or None)

Requirements Checklist

Import types from typing module
Add parameter type hints to functions
Add return type hints (-> type)
Use List, Dict, or other collection types
Use Optional for nullable values
Add type hints to variables
Output
# Click "Run Code" to execute your Python code
Hints & Tips
• Import: from typing import List, Dict, Optional
• Param: def func(name: str):
• Return: def func() -> int:
• List: List[str] Dict: Dict[str, int]
• Nullable: Optional[str] = str | None
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below