"Python embraces many functional programming concepts to enable cleaner and more declarative code. While not a purely functional language, it incorporates tools that treat functions as first-class citizens and focus on transforming data."- Gemini 2025
Functional programming is a programming paradigm that treats computation as the evaluation of mathematical functions and avoids changing state and mutable data.
# Pure function - same input, same output def add_pure(a, b): return a + b # Impure function - depends on external state counter = 0 def add_impure(a, b): global counter counter += 1 return a + b + counter # Pure function usage result1 = add_pure(2, 3) # Always returns 5 result2 = add_pure(2, 3) # Always returns 5 print(f"Pure: {result1}, {result2}") # Impure function usage result3 = add_impure(2, 3) # Returns 6 (2+3+1) result4 = add_impure(2, 3) # Returns 7 (2+3+2) print(f"Impure: {result3}, {result4}")
Lambda expressions are small anonymous functions that can have any number of arguments but can only have one expression.
# Basic syntax: lambda arguments: expression # Simple lambda square = lambda x: x ** 2 print(f"Square of 5: {square(5)}") # Lambda with multiple arguments multiply = lambda x, y: x * y print(f"3 * 4 = {multiply(3, 4)}") # Lambda with conditional max_value = lambda a, b: a if a > b else b print(f"Max of 10 and 15: {max_value(10, 15)}") # Using lambda in sorting students = [('Alice', 85), ('Bob', 90), ('Charlie', 78)] students.sort(key=lambda student: student[1]) # Sort by grade print(f"Sorted by grade: {students}") # Lambda in list operations numbers = [1, 2, 3, 4, 5] doubled = list(map(lambda x: x * 2, numbers)) print(f"Doubled numbers: {doubled}")
List comprehension provides a concise way to create lists based on existing lists or other iterables.
# Basic syntax: [expression for item in iterable if condition] # Basic list comprehension numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] squares = [x**2 for x in numbers] print(f"Squares: {squares}") # With condition evens = [x for x in numbers if x % 2 == 0] print(f"Even numbers: {evens}") # More complex expression formatted = [f"Number: {x}" for x in numbers if x > 5] print(f"Formatted: {formatted}") # Nested list comprehension matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] flattened = [item for row in matrix for item in row] print(f"Flattened matrix: {flattened}") # Dictionary comprehension word_lengths = {word: len(word) for word in ['python', 'java', 'javascript']} print(f"Word lengths: {word_lengths}") # Set comprehension unique_squares = {x**2 for x in [1, 2, 2, 3, 3, 4]} print(f"Unique squares: {unique_squares}")
These are built-in functions that allow functional programming approaches to data processing.
from functools import reduce numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # MAP: Apply function to all elements # map(function, iterable) squared = list(map(lambda x: x**2, numbers)) print(f"Map - Squared: {squared}") # Convert to strings str_numbers = list(map(str, numbers)) print(f"Map - Strings: {str_numbers}") # FILTER: Filter elements based on condition # filter(function, iterable) evens = list(filter(lambda x: x % 2 == 0, numbers)) print(f"Filter - Evens: {evens}") # Filter strings by length words = ['cat', 'elephant', 'dog', 'hippopotamus'] long_words = list(filter(lambda w: len(w) > 5, words)) print(f"Filter - Long words: {long_words}") # REDUCE: Reduce iterable to single value # reduce(function, iterable, initial_value) total = reduce(lambda x, y: x + y, numbers) print(f"Reduce - Sum: {total}") max_value = reduce(lambda x, y: x if x > y else y, numbers) print(f"Reduce - Max: {max_value}") # Combining map, filter, and reduce result = reduce( lambda x, y: x + y, map(lambda x: x**2, filter(lambda x: x % 2 == 0, numbers) ) ) print(f"Combined - Sum of squares of evens: {result}")
Objects that implement the iterator protocol (__iter__ and __next__ methods).
Functions that return an iterator using the yield keyword. Memory efficient!
# Custom Iterator Class class CountUp: def __init__(self, start, end): self.current = start self.end = end def __iter__(self): return self def __next__(self): if self.current < self.end: num = self.current self.current += 1 return num else: raise StopIteration # Using the iterator counter = CountUp(1, 5) for num in counter: print(f"Iterator: {num}") # Generator Function def fibonacci_generator(n): a, b = 0, 1 count = 0 while count < n: yield a a, b = b, a + b count += 1 # Using the generator print("Generator - Fibonacci sequence:") for fib in fibonacci_generator(8): print(fib, end=' ') print() # Generator Expression squares_gen = (x**2 for x in range(5)) print(f"Generator expression: {list(squares_gen)}") # Generator with infinite sequence def infinite_counter(): count = 0 while True: yield count count += 1 # Take only first 5 values counter_gen = infinite_counter() first_five = [next(counter_gen) for _ in range(5)] print(f"Infinite generator (first 5): {first_five}") # Memory efficiency demonstration import sys list_comp = [x**2 for x in range(1000)] gen_expr = (x**2 for x in range(1000)) print(f"List comprehension size: {sys.getsizeof(list_comp)} bytes") print(f"Generator expression size: {sys.getsizeof(gen_expr)} bytes")
The collections module provides specialized container datatypes providing alternatives to Python's general purpose built-in containers.
from collections import Counter, defaultdict, namedtuple, deque, OrderedDict # COUNTER: Count occurrences text = "hello world" letter_count = Counter(text) print(f"Counter: {letter_count}") print(f"Most common: {letter_count.most_common(3)}") # DEFAULTDICT: Dictionary with default values dd = defaultdict(list) words = ['apple', 'banana', 'apple', 'cherry', 'banana'] for word in words: dd[word[0]].append(word) # Group by first letter print(f"DefaultDict: {dict(dd)}") # NAMEDTUPLE: Immutable objects with named fields Person = namedtuple('Person', ['name', 'age', 'city']) john = Person('John', 30, 'New York') print(f"NamedTuple: {john}") print(f"Name: {john.name}, Age: {john.age}") # DEQUE: Double-ended queue (efficient append/pop from both ends) dq = deque(['a', 'b', 'c']) dq.appendleft('z') # Add to left dq.append('d') # Add to right print(f"Deque: {dq}") print(f"Pop left: {dq.popleft()}, Pop right: {dq.pop()}") print(f"Final deque: {dq}") # ORDEREDDICT: Dictionary that remembers insertion order (Python 3.7+ dicts are ordered) od = OrderedDict() od['first'] = 1 od['second'] = 2 od['third'] = 3 print(f"OrderedDict: {od}") # Practical example: Word frequency analysis def analyze_text(text): words = text.lower().split() word_freq = Counter(words) word_groups = defaultdict(list) for word, freq in word_freq.items(): word_groups[freq].append(word) return word_freq, dict(word_groups) sample_text = "the quick brown fox jumps over the lazy dog the fox is quick" freq, groups = analyze_text(sample_text) print(f"Word frequency: {freq}") print(f"Grouped by frequency: {groups}")
PyQt5 is more robust across different environments and systems.
# pip install pyqt5 import sys from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QPushButton class SimpleGUI(QWidget): def __init__(self): super().__init__() self.setWindowTitle('Simple GUI') self.setGeometry(300, 300, 250, 150) # Create layout layout = QVBoxLayout() # Create label self.label = QLabel('Hello, World!') layout.addWidget(self.label) # Create button button = QPushButton('Click Me!') button.clicked.connect(self.button_clicked) layout.addWidget(button) self.setLayout(layout) def button_clicked(self): self.label.setText('Button was clicked!') if __name__ == '__main__': app = QApplication(sys.argv) window = SimpleGUI() window.show() sys.exit(app.exec_())