Building Functional Code – Control Structures and Data Management
In this second section, we shift from basics to practical programming. Here, you’ll learn to add logic and structure to your code using control flow tools like conditionals (if/elif/else
) and loops (for
, while
). We’ll dive into functions – reusable blocks of code that streamline complex tasks – and explore data structures (lists, dictionaries, tuples, sets) to organize information efficiently. You’ll also master file handling, learning to read/write files (CSV, text) and manage data persistence. This section bridges theory and practice, teaching you to build programs that handle real-world scenarios, like processing datasets or automating repetitive tasks. By the end, you’ll be crafting clean, modular code that’s both functional and maintainable.
- Review: Part 1: Getting Started with Python (Installation, Data Types & Operators)
- Next: Part 3: Advanced Python (Data Science, ML & Debugging)
5. Control Flow in Python
Control flow statements determine the order in which code is executed.
5.1 if/elif/else Statements
- Conditional execution of code
- Can be nested
- Python uses indentation (4 spaces recommended) to define code blocks.
- Missing or inconsistent indentation causes errors.
# Grade calculator score = 85 if score >= 90: grade = 'A' print("Excellent!") elif score >= 80: grade = 'B' print("Good job!") elif score >= 70: grade = 'C' print("Satisfactory") else: grade = 'F' print("Need improvement") print(f"Grade: {grade}")
5.2 for Loops
- Iterate over sequences (lists, tuples, strings, etc.)
- range() function for numeric iterations
- Can use break, continue, and else clauses
# Iterating over a list with enumerate fruits = ["apple", "banana", "orange"] print("Fruit inventory:") for index, fruit in enumerate(fruits, 1): print(f"{index}. {fruit}") # Nested loop with break and continue print("\nMultiplication table (1-5):") for i in range(1, 6): if i == 3: continue for j in range(1, 6): if j == 4: break print(f"{i} x {j} = {i*j}", end="\t") print() # For loop with else print("\nSearching for a number:") numbers = [1, 3, 5, 7, 9] search_for = 4 for num in numbers: if num == search_for: print(f"Found {search_for}!") break else: print(f"{search_for} not found in the list")
5.3 while Loops
- Execute while condition is True
- Can use break and continue
- Requires careful condition management
# Countdown with while countdown = 5 print("Countdown starting...") while countdown > 0: print(f"{countdown}...") countdown -= 1 print("Liftoff!") # While loop with sentinel value print("\nEnter numbers to sum (0 to stop):") total = 0 while True: num = 7 # Simulating input, replace with actual input() in interactive mode if num == 0: break total += num print(f"Running total: {total}") break # Added for demonstration, remove in interactive mode
6. Functions in Python
Functions are reusable blocks of code that perform specific tasks.
- Built-in functions: Pre-defined functions in Python
- User-defined functions: Custom functions created by users
- Can have default parameters
- Can return multiple values
- Support type hints (Python 3.5+)
- Lambda functions: Small anonymous functions
- Single expression only
- Can be used as function arguments
6.1 Defining Functions
def greet(name: str, greeting: str = "Hello") -> str: """ Returns a greeting message for the specified name. Args: name: The name to greet greeting: The greeting to use (default: "Hello") Returns: A formatted greeting message """ return f"{greeting}, {name}!" message = greet("Alice") print(message)
6.2 Function Parameters
Functions can accept different types of parameters:
- Required parameters: Must be provided when calling the function.
- Default parameters: Have a default value assigned, making them optional.
- Keyword arguments: Passed with the parameter name, allowing you to specify arguments in any order.
- Variable-length arguments (*args, **kwargs): Allow you to pass an arbitrary number of positional or keyword arguments. *args collects extra positional arguments into a tuple, and **kwargs collects extra keyword arguments into a dictionary.
Function examples
print("\n=== Enhanced Function Examples ===") # Function with default parameters and type hints def greet(name: str, greeting: str = "Hello") -> str: """ Create a personalized greeting. Args: name (str): The name of the person to greet greeting (str, optional): The greeting to use. Defaults to "Hello" Returns: str: The complete greeting """ return f"{greeting}, {name}!" print(greet("Alice")) print(greet("Bob", greeting="Hi"))
Function with multiple return values
def analyze_numbers(numbers: list) -> tuple: """ Analyze a list of numbers. Args: numbers (list): List of numbers to analyze Returns: tuple: (minimum, maximum, average) """ if not numbers: return None, None, None return min(numbers), max(numbers), sum(numbers)/len(numbers) numbers = [1, 5, 3, 7, 2] min_val, max_val, avg = analyze_numbers(numbers) print(f"\nNumber analysis: min={min_val}, max={max_val}, avg={avg:.2f}")
Function with *args and **kwargs
def format_info(*args, **kwargs) -> str: """ Format information from variable arguments. Args: *args: Variable positional arguments **kwargs: Variable keyword arguments Returns: str: Formatted information """ positional = ", ".join(str(arg) for arg in args) keyword = ", ".join(f"{k}={v}" for k, v in kwargs.items()) return f"Positional: {positional}\nKeyword: {keyword}" print(format_info(1, 2, 3, name="Alice", age=25))
lambda examples
# Lambda with map numbers = [1, 2, 3, 4, 5] squares = list(map(lambda x: x**2, numbers)) print(f"Original: {numbers}") print(f"Squares: {squares}") # Lambda with filter even_numbers = list(filter(lambda x: x % 2 == 0, numbers)) print(f"Even numbers: {even_numbers}") # Lambda with sorting points = [(1, 2), (3, 1), (2, 4)] sorted_points = sorted(points, key=lambda p: p[1]) # Sort by y-coordinate print(f"Sorted points by y: {sorted_points}")
7. Python Data Structures
Python offers several built-in data structures for organizing and managing data.
7.1. Lists
Python lists are ordered, mutable sequences created with square brackets []
, ideal for storing and managing dynamic datasets. They support mixed data types (e.g., integers, strings, even other lists) and allow duplicate values. Elements are accessed via zero-based indexing, and their mutability enables powerful in-place operations like adding (append()
, extend()
, insert()
), removing (remove()
, pop()
, clear()
), searching (index()
, count()
), and reorganizing (sort()
, reverse()
). Lists strike a balance between simplicity and versatility, making them indispensable for everything from simple to-do lists to complex data structures.
Lists Examples
print("\n=== Lists ===") # Creating and modifying lists fruits = ["apple", "banana", "orange"] print(f"Original list: {fruits}") # Adding elements fruits.append("grape") # Add single element fruits.extend(["kiwi", "mango"]) # Add multiple elements fruits.insert(1, "pear") # Insert at specific position print(f"After adding: {fruits}") # Removing elements fruits.remove("banana") # Remove by value popped = fruits.pop() # Remove and return last element print(f"After removing: {fruits}") print(f"Popped element: {popped}") # List operations numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5] print(f"\nNumbers: {numbers}") print(f"Count of 5: {numbers.count(5)}") print(f"Index of first 5: {numbers.index(5)}") numbers.sort() print(f"Sorted: {numbers}") numbers.reverse() print(f"Reversed: {numbers}") # List slicing print(f"First 3 elements: {numbers[:3]}") print(f"Last 3 elements: {numbers[-3:]}") print(f"Every second element: {numbers[::2]}")
7.2. Tuples
Python tuples are ordered, immutable collections defined with parentheses ()
(or commas alone). They store mixed data types and permit duplicates, but once created, their elements cannot be altered. This immutability makes them faster than lists for fixed data and ideal for representing related values (e.g., coordinates (x, y)
) or as dictionary keys. Common operations like index()
and count()
enable element retrieval and analysis, while their structure shines in scenarios requiring multiple return values from functions or hashable data integrity. Tuples balance efficiency with simplicity for static, structured data.
Tuples Examples
print("\n=== Tuples ===") # Creating tuples point = (3, 4) person = ("John", 30, "New York") single_element = (42,) # Note the comma print(f"Point: {point}") print(f"Person: {person}") print(f"Single element: {single_element}") # Tuple unpacking x, y = point name, age, city = person print(f"Unpacked point: x={x}, y={y}") print(f"Unpacked person: name={name}, age={age}, city={city}") # Tuple as dictionary key locations = { (40.7128, -74.0060): "New York", (51.5074, -0.1278): "London" } print(f"\nLocations dictionary: {locations}")
7.3. Sets
Python sets are unordered, mutable groups of unique elements, created with curly braces {}
or set()
. They enforce uniqueness, duplicates are automatically removed and excel at membership checks and mathematical operations like unions (union()
), intersections (intersection()
), and differences (difference()
). While they lack indexing due to their unordered nature, their mutability allows dynamic modification via methods like add()
, remove()
, and update()
. Sets shine in tasks requiring duplicate elimination, fast lookups, or comparisons between datasets, making them ideal for data cleansing, analytics, and algorithm optimization.
Sets Examples
print("\n=== Sets ===") # Creating and modifying sets numbers_set = {1, 2, 3, 2, 1} # Duplicates are automatically removed print(f"Original set: {numbers_set}") # Set operations numbers_set.add(4) numbers_set.update([5, 6, 4]) # Adding multiple elements print(f"After adding: {numbers_set}") # Set mathematics set1 = {1, 2, 3, 4} set2 = {3, 4, 5, 6} print(f"\nSet 1: {set1}") print(f"Set 2: {set2}") print(f"Union: {set1 | set2}") print(f"Intersection: {set1 & set2}") print(f"Difference (set1 - set2): {set1 - set2}") print(f"Symmetric difference: {set1 ^ set2}") # Set operations with methods print(f"Is set1 subset of set2? {set1.issubset(set2)}") print(f"Is set1 disjoint from set2? {set1.isdisjoint(set2)}")
7.4. Dictionaries
Python dictionaries are mutable, unordered collections of unique key-value pairs, created with curly braces {}
. Keys must be immutable (e.g., strings, numbers, tuples) and unique, while values can be any data type. Dictionaries excel at fast lookups via hash table implementation, making them ideal for storing structured data (e.g., user profiles, configurations). Common operations include accessing keys/values (keys()
, values()
, items()
), safe value retrieval (get()
), merging (update()
), and dynamic modification (pop()
, setdefault()
). While unordered in Python <3.7, they remain indispensable for efficient data mapping and JSON-like data handling.
Dictionaries Examples
print("\n=== Dictionaries ===") # Creating and modifying dictionaries person = { 'name': 'John', 'age': 30, 'city': 'New York', 'skills': ['Python', 'JavaScript'] } # Dictionary operations print(f"Original dictionary: {person}") person['email'] = 'john@example.com' # Adding new key-value pair person.update({'age': 31, 'phone': '123-456-7890'}) # Update multiple keys print(f"After updates: {person}") # Safe dictionary access print(f"\nSafe access examples:") print(f"Name: {person.get('name', 'Unknown')}") print(f"Salary: {person.get('salary', 'Not specified')}") # Dictionary methods print(f"\nDictionary methods:") print(f"Keys: {list(person.keys())}") print(f"Values: {list(person.values())}") print(f"Items: {list(person.items())}") # Dictionary comprehension with conditions squares = {x: x**2 for x in range(5) if x % 2 == 0} print(f"\nEven number squares: {squares}") # Nested dictionaries employees = { 'emp1': {'name': 'Alice', 'role': 'Developer'}, 'emp2': {'name': 'Bob', 'role': 'Designer'} } print(f"\nNested dictionary: {employees}") print(f"emp1's role: {employees['emp1']['role']}")
8. File Handling in Python
Python provides robust tools for reading from and writing to files, enabling persistent data storage and retrieval. Files are accessed through modes that define their use case:
Core Modes
- Read (
'r'
): Open an existing file for reading (default mode). - Write (
'w'
): Create a new file or overwrite an existing one. - Append (
'a'
): Add content to the end of an existing file. - Binary (
'b'
): Handle non-text files (e.g., images) using bytes. - Update (
'+'
): Combine reading and writing (e.g.,'r+'
or'w+'
).
Basic Workflow
- Opening Files: Use
open(filename, mode)
to create a file object. - Reading/Writing:
read()
loads the entire content as a string.write()
adds data to the file.
- Closing: Always call
close()
to free system resources.
Best Practice – Context Managers
The with
statement ensures automatic cleanup, even if errors occur:
# Writing text to a file print("Writing to file...") # Output: Writing to file... with open("example.txt", "w") as file: file.write("Hello, this is line 1\n") # Write single line # Writing multiple lines lines = [ "This is line 2\n", "This is line 3\n", "This is line 4" ] file.writelines(lines) # Note: No immediate output as we're writing to file # File content will be: # Hello, this is line 1 # This is line 2 # This is line 3 # This is line 4 # Reading entire file print("\nReading entire file:") # Output: Reading entire file: with open("example.txt", "r") as file: content = file.read() print(content) # Output: # Hello, this is line 1 # This is line 2 # This is line 3 # This is line 4 # Reading line by line print("\nReading line by line:") # Output: Reading line by line: with open("example.txt", "r") as file: for line_number, line in enumerate(file, 1): print(f"Line {line_number}: {line.strip()}") # Output: # Line 1: Hello, this is line 1 # Line 2: This is line 2 # Line 3: This is line 3 # Line 4: This is line 4 # Appending to file print("\nAppending to file...") # Output: Appending to file... with open("example.txt", "a") as file: file.write("\nThis line is appended") # File now contains an additional line: # This line is appended # Reading with specific encoding print("\nReading with UTF-8 encoding:") # Output: Reading with UTF-8 encoding: with open("example.txt", "r", encoding="utf-8") as file: content = file.read() print(content) # Output: # Hello, this is line 1 # This is line 2 # This is line 3 # This is line 4 # This line is appended # Working with CSV files import csv # Writing CSV print("\nWriting CSV file...") # Output: Writing CSV file... data = [ ['Name', 'Age', 'City'], ['John', '25', 'New York'], ['Alice', '30', 'London'], ['Bob', '35', 'Paris'] ] with open("data.csv", "w", newline='') as file: writer = csv.writer(file) writer.writerows(data) # CSV file content will be: # Name,Age,City # John,25,New York # Alice,30,London # Bob,35,Paris # Reading CSV print("\nReading CSV file:") # Output: Reading CSV file: with open("data.csv", "r") as file: reader = csv.reader(file) for row in reader: print(f"Row: {row}") # Output: # Row: ['Name', 'Age', 'City'] # Row: ['John', '25', 'New York'] # Row: ['Alice', '30', 'London'] # Row: ['Bob', '35', 'Paris'] # Error handling in file operations print("\nDemonstrating error handling:") # Output: Demonstrating error handling: try: with open("nonexistent.txt", "r") as file: content = file.read() except FileNotFoundError: print("Error: File not found!") # Output: Error: File not found! except PermissionError: print("Error: Permission denied!") except Exception as e: print(f"Error: {str(e)}") finally: print("File operation completed") # Output: File operation completed # Binary file operations print("\nBinary file operations:") # Output: Binary file operations: # Writing binary data with open("binary.dat", "wb") as file: file.write(bytes([65, 66, 67, 68])) # Writing ASCII values for 'ABCD' # No immediate output - writing binary data # Reading binary data with open("binary.dat", "rb") as file: binary_data = file.read() print(f"Binary data (ASCII): {binary_data}") # Output: Binary data (ASCII): b'ABCD' print(f"Decoded data: {binary_data.decode('ascii')}") # Output: Decoded data: ABCD
Conclusion: Control Flow & Data Structures
You’ve leveled up! With control flow, functions, and data structures under your belt, you can now write programs that make decisions, repeat tasks efficiently, and handle real-world data like CSV files. These skills transform you from a coder who writes lines to a developer who solves problems.
What’s Next?
In the final installment: Advanced Python, you’ll debug like a pro, optimize code for speed, and dive into the thrilling world of machine learning. Imagine building models that predict trends or classify images, it’s all within your reach.
“Great code isn’t written – it’s debugged, refined, and celebrated. Onward!”