paradigm_comparison.py

Download
python 268 lines 8.3 KB
  1"""
  2Programming Paradigm Comparison
  3
  4Problem: Given a list of numbers, filter out negatives, square the positives,
  5and return the sum of squares.
  6
  7This demonstrates the same problem solved using:
  81. Imperative Programming (step-by-step instructions)
  92. Object-Oriented Programming (data + behavior encapsulation)
 103. Functional Programming (pure functions + composition)
 11"""
 12
 13from typing import List
 14from functools import reduce
 15
 16
 17# =============================================================================
 18# 1. IMPERATIVE STYLE: Focus on HOW to do it (step-by-step)
 19# =============================================================================
 20
 21def imperative_approach(numbers: List[int]) -> int:
 22    """
 23    Imperative style uses explicit loops and mutable state.
 24    We tell the computer exactly WHAT to do at each step.
 25    """
 26    # Step 1: Create mutable accumulator
 27    result = 0
 28
 29    # Step 2: Iterate through each number
 30    for num in numbers:
 31        # Step 3: Check condition
 32        if num > 0:
 33            # Step 4: Transform (square)
 34            squared = num * num
 35            # Step 5: Accumulate
 36            result += squared
 37
 38    return result
 39
 40
 41# =============================================================================
 42# 2. OBJECT-ORIENTED STYLE: Focus on objects with data + behavior
 43# =============================================================================
 44
 45class NumberProcessor:
 46    """
 47    OOP encapsulates data and operations together.
 48    State is managed within the object.
 49    """
 50
 51    def __init__(self, numbers: List[int]):
 52        self._numbers = numbers
 53        self._filtered = []
 54        self._squared = []
 55        self._sum = 0
 56
 57    def filter_positives(self) -> 'NumberProcessor':
 58        """Remove negative numbers (method chaining support)"""
 59        self._filtered = [n for n in self._numbers if n > 0]
 60        return self
 61
 62    def square_values(self) -> 'NumberProcessor':
 63        """Square each value"""
 64        self._squared = [n * n for n in self._filtered]
 65        return self
 66
 67    def calculate_sum(self) -> 'NumberProcessor':
 68        """Calculate sum of all values"""
 69        self._sum = sum(self._squared)
 70        return self
 71
 72    def get_result(self) -> int:
 73        """Return final result"""
 74        return self._sum
 75
 76
 77def oop_approach(numbers: List[int]) -> int:
 78    """
 79    OOP style uses objects to encapsulate state and behavior.
 80    Supports method chaining for fluent interface.
 81    """
 82    processor = NumberProcessor(numbers)
 83    return (processor
 84            .filter_positives()
 85            .square_values()
 86            .calculate_sum()
 87            .get_result())
 88
 89
 90# =============================================================================
 91# 3. FUNCTIONAL STYLE: Focus on WHAT to compute (composition of functions)
 92# =============================================================================
 93
 94def is_positive(n: int) -> bool:
 95    """Pure function: same input always returns same output"""
 96    return n > 0
 97
 98
 99def square(n: int) -> int:
100    """Pure function: no side effects"""
101    return n * n
102
103
104def add(a: int, b: int) -> int:
105    """Pure function for reduction"""
106    return a + b
107
108
109def functional_approach(numbers: List[int]) -> int:
110    """
111    Functional style uses pure functions and function composition.
112    No mutable state, no side effects.
113    Data flows through transformations.
114    """
115    return reduce(
116        add,
117        map(square, filter(is_positive, numbers)),
118        0  # initial value
119    )
120
121
122def functional_approach_comprehension(numbers: List[int]) -> int:
123    """
124    Alternative functional style using list comprehension
125    (more Pythonic, still functionally pure)
126    """
127    return sum(n * n for n in numbers if n > 0)
128
129
130# =============================================================================
131# COMPARISON & DEMONSTRATION
132# =============================================================================
133
134def compare_paradigms():
135    """Compare all three paradigms with the same input"""
136
137    test_data = [-5, 3, -2, 8, 0, 4, -1, 6]
138
139    print("=" * 70)
140    print("PROGRAMMING PARADIGM COMPARISON")
141    print("=" * 70)
142    print(f"\nInput: {test_data}")
143    print(f"Task: Filter positives → Square → Sum\n")
144
145    # Test all approaches
146    imperative_result = imperative_approach(test_data)
147    oop_result = oop_approach(test_data)
148    functional_result = functional_approach(test_data)
149    functional_comp_result = functional_approach_comprehension(test_data)
150
151    print("RESULTS:")
152    print(f"  Imperative:        {imperative_result}")
153    print(f"  Object-Oriented:   {oop_result}")
154    print(f"  Functional:        {functional_result}")
155    print(f"  Functional (comp): {functional_comp_result}")
156
157    # Verify all give same result
158    assert imperative_result == oop_result == functional_result == functional_comp_result
159    print("\n✓ All paradigms produce identical results!\n")
160
161    # Show step-by-step breakdown
162    print("STEP-BY-STEP BREAKDOWN:")
163    positives = [n for n in test_data if n > 0]
164    print(f"  1. Filter positives: {positives}")
165    squares = [n * n for n in positives]
166    print(f"  2. Square values:    {squares}")
167    total = sum(squares)
168    print(f"  3. Sum:              {total}")
169
170    print("\n" + "=" * 70)
171    print("PARADIGM CHARACTERISTICS")
172    print("=" * 70)
173
174    print("\nIMPERATIVE:")
175    print("  ✓ Explicit control flow (loops, conditionals)")
176    print("  ✓ Mutable state (variables change)")
177    print("  ✓ Step-by-step instructions")
178    print("  ✓ Easy to debug (can inspect each step)")
179    print("  ✗ More verbose")
180    print("  ✗ Harder to parallelize")
181
182    print("\nOBJECT-ORIENTED:")
183    print("  ✓ Encapsulation (data + behavior together)")
184    print("  ✓ Reusable objects")
185    print("  ✓ Method chaining (fluent interface)")
186    print("  ✓ Good for complex state management")
187    print("  ✗ Can be over-engineered for simple tasks")
188    print("  ✗ Mutable state can lead to bugs")
189
190    print("\nFUNCTIONAL:")
191    print("  ✓ Pure functions (no side effects)")
192    print("  ✓ Immutable data")
193    print("  ✓ Function composition")
194    print("  ✓ Easy to test and parallelize")
195    print("  ✓ Declarative (what, not how)")
196    print("  ✗ Can be less intuitive initially")
197    print("  ✗ May use more memory (creates new data)")
198
199    print("\n" + "=" * 70)
200    print("WHEN TO USE EACH PARADIGM")
201    print("=" * 70)
202
203    print("\nIMPERATIVE:")
204    print("  • Performance-critical code")
205    print("  • Systems programming")
206    print("  • When you need fine-grained control")
207
208    print("\nOBJECT-ORIENTED:")
209    print("  • Complex state management")
210    print("  • Modeling real-world entities")
211    print("  • Large codebases with multiple developers")
212    print("  • GUI applications")
213
214    print("\nFUNCTIONAL:")
215    print("  • Data transformation pipelines")
216    print("  • Concurrent/parallel processing")
217    print("  • Mathematical computations")
218    print("  • When immutability is important")
219
220
221def demonstrate_hybrid_approach():
222    """
223    Modern programming often uses a HYBRID approach,
224    combining the best of all paradigms.
225    """
226    print("\n" + "=" * 70)
227    print("HYBRID APPROACH (Real-world Python)")
228    print("=" * 70)
229
230    class DataPipeline:
231        """OOP structure with functional transformations"""
232
233        def __init__(self, data: List[int]):
234            self.data = data
235
236        def process(self) -> int:
237            """Functional operations within OOP structure"""
238            return sum(n * n for n in self.data if n > 0)
239
240    test_data = [-5, 3, -2, 8, 0, 4]
241    pipeline = DataPipeline(test_data)
242    result = pipeline.process()
243
244    print(f"\nInput: {test_data}")
245    print(f"Result: {result}")
246    print("\nThis combines:")
247    print("  • OOP: Class structure for organization")
248    print("  • Functional: Pure transformation with comprehension")
249    print("  • Imperative: Hidden in Python's built-in functions")
250    print("\nMost modern code uses this pragmatic mix!")
251
252
253if __name__ == "__main__":
254    compare_paradigms()
255    demonstrate_hybrid_approach()
256
257    print("\n" + "=" * 70)
258    print("KEY TAKEAWAY")
259    print("=" * 70)
260    print("""
261Paradigms are TOOLS, not religions.
262Choose based on the problem:
263  • Imperative for control and performance
264  • OOP for modeling and state management
265  • Functional for transformations and safety
266  • Hybrid for real-world pragmatism
267""")