PYnative

Python Programming

  • Learn Python
    • Python Tutorials
    • Python Basics
    • Python Interview Q&As
  • Exercises
    • Python Exercises
    • C Programming Exercises
    • C++ Exercises
  • Quizzes
  • Code Editor
    • Online Python Code Editor
    • Online C Compiler
    • Online C++ Compiler
Home » Python Exercises » Python OS and Sys Module Exercises: 30 Coding Problems with Solutions

Python OS and Sys Module Exercises: 30 Coding Problems with Solutions

Updated on: June 13, 2026 | Leave a Comment

This article presents 30 coding exercises that teach you to work with Python’s os and sys modules — the foundation of any practical scripting or automation work. Topics covered include file and directory operations such as creating, renaming, deleting, and traversing directory trees; reading and setting environment variables; handling command-line arguments with sys.argv; platform detection; managing the module search path with sys.path; and controlling interpreter behaviour through recursion limits and exit codes.

Each coding challenge includes a Practice Problem, Hint, Solution code, and detailed Explanation, ensuring you don’t just copy code, but genuinely practice and understand how and why it works.

  • All solutions have been fully tested on Python 3.
  • Use our Online Code Editor to solve these exercises in real time.
  • Also, Solve Python Exercises: 29 topic-wise exercises with over 800+ coding questions

Let us know if you have any alternative solutions. It will help other developers.

+ Table of Contents (30 Exercises)

Table of contents

  • Exercise 1: Print Current Directory
  • Exercise 2: List Directory Contents
  • Exercise 3: Create a Directory
  • Exercise 4: Create Nested Directories
  • Exercise 5: Rename a File
  • Exercise 6: Delete a File
  • Exercise 7: Delete a Directory Tree
  • Exercise 8: Check Path Existence
  • Exercise 9: Split File Extension
  • Exercise 10: Get File Size
  • Exercise 11: Read an Environment Variable
  • Exercise 12: Set an Environment Variable
  • Exercise 13: List All Environment Variables
  • Exercise 14: Get Current Process ID
  • Exercise 15: Run a Shell Command
  • Exercise 16: Walk a Directory Tree
  • Exercise 17: Join Paths Safely
  • Exercise 18: Get Absolute Path
  • Exercise 19: Print Python Version
  • Exercise 20: Read Command-Line Arguments
  • Exercise 21: Exit a Program
  • Exercise 22: Get Platform Info
  • Exercise 23: Inspect sys.path
  • Exercise 24: Add to sys.path
  • Exercise 25: Get Recursion Limit
  • Exercise 26: Change Recursion Limit
  • Exercise 27: Script Info Logger
  • Exercise 28: Directory Size Calculator
  • Exercise 29: Environment Config Loader
  • Exercise 30: Recursive File Finder

Exercise 1: Print Current Directory

Problem Statement: Write a Python program that prints the current working directory to the console.

Purpose: This exercise introduces the os module and its most fundamental function. Knowing how to retrieve the current working directory is a foundational skill for file I/O operations, path construction, and building scripts that need to locate resources relative to where they run.

Given Input: No input required. The function reads the environment directly.

Expected Output: /home/user/projects (the actual path will vary based on your system)

▼ Hint
  • Import the os module at the top of your script.
  • Use os.getcwd() to retrieve the current working directory as a string.
  • Pass the result directly to print().
▼ Solution & Explanation
import os

cwd = os.getcwd()
print("Current Directory:", cwd)Code language: Python (python)

Explanation:

  • import os: Loads Python’s built-in os module, which provides functions for interacting with the operating system.
  • os.getcwd(): Stands for “get current working directory.” It returns an absolute path string representing the directory from which the script is being run.
  • print("Current Directory:", cwd): Displays the path in a readable format. The output will differ depending on your OS and the folder where the script is executed.

Exercise 2: List Directory Contents

Problem Statement: Write a Python program that lists all files and folders in a given directory path.

Purpose: This exercise teaches you to inspect a directory’s contents programmatically. It is a core skill for building file managers, automation scripts, batch processors, and any tool that needs to discover what files are available at runtime.

Given Input: path = "." (the current directory)

Expected Output: A printed list of all file and folder names in the specified directory (output varies by system).

▼ Hint
  • Use os.listdir(path) to get a list of all entries in the given directory.
  • Iterate over the returned list with a for loop and print each item.
  • The list includes both files and subdirectories, but does not recurse into subdirectories.
▼ Solution & Explanation
import os

path = "."
contents = os.listdir(path)

for item in contents:
    print(item)Code language: Python (python)

Explanation:

  • os.listdir(path): Returns a Python list of strings, where each string is the name of a file or subfolder inside path. It does not include . or .. entries.
  • for item in contents: Iterates over each entry in the list returned by listdir(), printing one name per line.
  • Note: The entries are not sorted by default. Wrap the call in sorted() if alphabetical order is needed: sorted(os.listdir(path)).

Exercise 3: Create a Directory

Problem Statement: Write a Python program that creates a new folder called test_folder in the current working directory, only if it does not already exist.

Purpose: Creating directories programmatically is essential for setting up output folders, organising generated files, and building scripts that prepare a workspace before writing data. Checking for existence first prevents crashes from duplicate creation.

Given Input: folder_name = "test_folder"

Expected Output: Folder 'test_folder' created successfully. or Folder 'test_folder' already exists.

▼ Hint
  • Use os.path.exists(folder_name) to check if the folder already exists before creating it.
  • If it does not exist, call os.mkdir(folder_name) to create it.
  • Use an if/else block to print the appropriate message in each case.
▼ Solution & Explanation
import os

folder_name = "test_folder"

if not os.path.exists(folder_name):
    os.mkdir(folder_name)
    print(f"Folder '{folder_name}' created successfully.")
else:
    print(f"Folder '{folder_name}' already exists.")Code language: Python (python)

Explanation:

  • os.path.exists(folder_name): Returns True if the given path (file or folder) already exists on disk, preventing a FileExistsError when calling mkdir().
  • os.mkdir(folder_name): Creates a single new directory at the specified path. It will raise a FileNotFoundError if any intermediate parent directories are missing – use os.makedirs() for nested paths instead.
  • f-strings: The f"..." syntax is used for clean, readable string formatting with the variable embedded directly.

Exercise 4: Create Nested Directories

Problem Statement: Write a Python program that creates a nested directory structure a/b/c in the current working directory, even if some or all of the parent directories do not yet exist.

Purpose: Real-world scripts frequently need to create deep folder hierarchies in a single step – for example, when organising output by date (logs/2025/06/10) or project structure. os.makedirs() handles this without requiring manual creation of each level.

Given Input: nested_path = "a/b/c"

Expected Output: Nested directories 'a/b/c' created successfully.

▼ Hint
  • Use os.makedirs(path) instead of os.mkdir() to create all intermediate directories in one call.
  • Pass exist_ok=True as a keyword argument to avoid an error if the directory already exists.
  • Use os.path.join() to build the path safely across different operating systems if needed.
▼ Solution & Explanation
import os

nested_path = os.path.join("a", "b", "c")

os.makedirs(nested_path, exist_ok=True)
print(f"Nested directories '{nested_path}' created successfully.")Code language: Python (python)

Explanation:

  • os.path.join("a", "b", "c"): Constructs the path using the correct separator for the current OS (/ on Unix, \ on Windows), making the script portable.
  • os.makedirs(nested_path, exist_ok=True): Creates all directories in the path recursively. The exist_ok=True argument suppresses the FileExistsError that would otherwise be raised if any part of the path already exists.
  • Difference from os.mkdir(): mkdir() can only create one level at a time and fails if a parent is missing. makedirs() handles the entire chain in a single call.

Exercise 5: Rename a File

Problem Statement: Write a Python program that renames a file called old.txt to new.txt in the current directory, with a check to confirm the source file exists before attempting the rename.

Purpose: Renaming files is a common task in file management scripts, data pipelines, and backup utilities. This exercise reinforces safe file handling by combining existence checks with the rename operation, preventing runtime errors on missing files.

Given Input: A file named old.txt must exist in the current directory.

Expected Output: Renamed 'old.txt' to 'new.txt' successfully. or Source file 'old.txt' does not exist.

▼ Hint
  • Use os.path.exists("old.txt") to verify the file is present before renaming.
  • Call os.rename(src, dst) where src is the current filename and dst is the new filename.
  • To test this, create old.txt first using open("old.txt", "w").close() at the top of your script.
▼ Solution & Explanation
import os

src = "old.txt"
dst = "new.txt"

# Create the file for testing purposes
open(src, "w").close()

if os.path.exists(src):
    os.rename(src, dst)
    print(f"Renamed '{src}' to '{dst}' successfully.")
else:
    print(f"Source file '{src}' does not exist.")Code language: Python (python)

Explanation:

  • open(src, "w").close(): Creates an empty file for testing. The "w" mode opens the file for writing, and .close() immediately closes it, leaving a zero-byte file on disk.
  • os.path.exists(src): Guards against a FileNotFoundError by confirming the source file is present before the rename is attempted.
  • os.rename(src, dst): Renames (or moves, if paths differ) the file atomically on most operating systems. If dst already exists, it will be silently overwritten on Unix but raise an error on Windows.

Exercise 6: Delete a File

Problem Statement: Write a Python program that deletes a file called temp.txt from the current directory, but only after verifying that the file actually exists.

Purpose: Safe file deletion is a critical skill in automation and cleanup scripts. Blindly calling a delete function without checking for existence will raise an exception and halt your program. This exercise builds the habit of defensive file operations.

Given Input: A file named temp.txt (created in the script for testing).

Expected Output: File 'temp.txt' deleted successfully. or File 'temp.txt' not found.

▼ Hint
  • Use os.path.exists(filename) to check if the file is present before deletion.
  • Call os.remove(filename) to delete the file. This works only on files, not directories.
  • To delete a directory, use os.rmdir() (empty only) or shutil.rmtree() (non-empty).
▼ Solution & Explanation
import os

filename = "temp.txt"

# Create the file for testing purposes
with open(filename, "w") as f:
    f.write("temporary content")

if os.path.exists(filename):
    os.remove(filename)
    print(f"File '{filename}' deleted successfully.")
else:
    print(f"File '{filename}' not found.")Code language: Python (python)

Explanation:

  • with open(filename, "w") as f: Creates the test file using a context manager, which automatically closes the file handle when the block exits – a best practice over manual .close() calls.
  • os.path.exists(filename): Returns True if the path points to an existing file or directory, letting you branch safely before the destructive operation.
  • os.remove(filename): Permanently deletes the specified file. It raises IsADirectoryError if the path points to a folder, so use the appropriate function based on what you are deleting.

Exercise 7: Delete a Directory Tree

Problem Statement: Write a Python program that creates a nested directory structure cleanup/a/b, adds a dummy file inside it, then removes the entire tree including all contents.

Purpose: Removing a directory and all of its contents is a frequent requirement in test teardown, temporary file cleanup, and build scripts. This exercise demonstrates the difference between os.rmdir() (empty directories only) and shutil.rmtree() (recursive deletion).

Given Input: Directory tree cleanup/a/b with a file cleanup/a/b/note.txt inside (created in the script).

Expected Output: Directory tree 'cleanup' removed successfully.

▼ Hint
  • Use os.makedirs() to create the nested directory and open() to create a dummy file inside it.
  • Import shutil and use shutil.rmtree(path) to recursively delete the entire directory including all files and subdirectories.
  • Use os.path.exists() before calling rmtree() to avoid errors if the directory is already gone.
▼ Solution & Explanation
import os
import shutil

base_dir = "cleanup"
nested_path = os.path.join(base_dir, "a", "b")

# Create the nested directory and a dummy file
os.makedirs(nested_path, exist_ok=True)
with open(os.path.join(nested_path, "note.txt"), "w") as f:
    f.write("temporary note")

# Remove the entire tree
if os.path.exists(base_dir):
    shutil.rmtree(base_dir)
    print(f"Directory tree '{base_dir}' removed successfully.")
else:
    print(f"Directory '{base_dir}' not found.")Code language: Python (python)

Explanation:

  • os.makedirs(nested_path, exist_ok=True): Creates the full cleanup/a/b path in one call. The exist_ok=True parameter prevents errors if the path was already created from a previous run.
  • shutil.rmtree(base_dir): Recursively deletes the entire directory tree rooted at base_dir, including all subdirectories and files. os.rmdir() would fail here because the directory is not empty.
  • import shutil: The shutil (shell utilities) module complements os with higher-level file operations like recursive copy and recursive delete, which the os module alone does not support.

Exercise 8: Check Path Existence

Problem Statement: Write a Python program that checks whether a given file or directory path exists on the system and prints a descriptive message indicating the result.

Purpose: Before performing any file operation – reading, writing, deleting, or renaming – it is good practice to verify that the target path actually exists. This exercise builds the habit of defensive path checking, which prevents FileNotFoundError crashes in production scripts.

Given Input: path = "sample.txt" (created in the script for testing)

Expected Output: Path 'sample.txt' exists. or Path 'sample.txt' does not exist.

▼ Hint
  • Use os.path.exists(path) to check for either a file or a directory at the given path.
  • For more specific checks, use os.path.isfile(path) to confirm it is a file, or os.path.isdir(path) to confirm it is a directory.
  • Use an if/else block to print the appropriate message for each case.
▼ Solution & Explanation
import os

path = "sample.txt"

# Create the file for testing purposes
with open(path, "w") as f:
    f.write("hello")

if os.path.exists(path):
    print(f"Path '{path}' exists.")
else:
    print(f"Path '{path}' does not exist.")Code language: Python (python)

Explanation:

  • os.path.exists(path): Returns True if the path points to an existing file or directory, and False otherwise. It also returns False for broken symbolic links.
  • os.path.isfile(path): A more targeted check that returns True only if the path exists and is a regular file – useful when you need to rule out directories.
  • os.path.isdir(path): Returns True only if the path exists and is a directory. Combining all three checks lets you build robust path-validation logic in larger scripts.

Exercise 9: Split File Extension

Problem Statement: Write a Python program that takes a filename string and extracts both the base name and the file extension separately.

Purpose: Parsing filenames is a routine task in file processing pipelines – for example, when filtering files by type, renaming files while preserving extensions, or routing files to different handlers based on format. This exercise introduces the clean, OS-aware way to split a filename.

Given Input: filename = "report_2025.pdf"

Expected Output: Base: report_2025 and Extension: .pdf

▼ Hint
  • Use os.path.splitext(filename) which returns a tuple of (root, ext).
  • The extension includes the leading dot, for example .pdf not pdf.
  • You can unpack the result directly: base, ext = os.path.splitext(filename).
▼ Solution & Explanation
import os

filename = "report_2025.pdf"

base, ext = os.path.splitext(filename)

print("Base:", base)
print("Extension:", ext)Code language: Python (python)

Explanation:

  • os.path.splitext(filename): Splits the filename at the last dot and returns a two-element tuple: the root name and the extension (including the dot). For "report_2025.pdf" it returns ('report_2025', '.pdf').
  • base, ext = ...: Tuple unpacking assigns both parts to separate variables in a single, readable line rather than using index access like [0] and [1].
  • Edge cases: For a file with no extension such as "README", ext will be an empty string "". For dotfiles like ".gitignore", the entire name is treated as the root with an empty extension.

Exercise 10: Get File Size

Problem Statement: Write a Python program that creates a file with some content and then prints its size in bytes.

Purpose: Checking file size is useful in scripts that enforce size limits, monitor disk usage, validate that a file was written correctly, or decide whether to process a file. This exercise shows how to retrieve file metadata without opening the file itself.

Given Input: A file named data.txt containing the text Hello, Python! (created in the script).

Expected Output: File size: 14 bytes

▼ Hint
  • Use os.path.getsize(filepath) to retrieve the file size in bytes as an integer.
  • Make sure the file exists before calling getsize(), otherwise it raises a FileNotFoundError.
  • To convert bytes to kilobytes, divide the result by 1024.
▼ Solution & Explanation
import os

filepath = "data.txt"

# Create the file for testing purposes
with open(filepath, "w") as f:
    f.write("Hello, Python!")

size = os.path.getsize(filepath)
print(f"File size: {size} bytes")Code language: Python (python)

Explanation:

  • os.path.getsize(filepath): Returns the size of the file at the given path in bytes as an integer. It reads from the filesystem metadata and does not need to open or read the file contents.
  • File size vs character count: The string "Hello, Python!" has 14 characters. In a UTF-8 encoded file each ASCII character occupies 1 byte, so the size is 14 bytes. Files with Unicode characters may have a larger byte size than their character count.
  • Practical extension: To display a human-readable size, divide by 1024 for KB, 1024 ** 2 for MB, and so on, then format with f"{size / 1024:.2f} KB".

Exercise 11: Read an Environment Variable

Problem Statement: Write a Python program that reads the system’s PATH environment variable and prints its value. If the variable is not found, print a default fallback message.

Purpose: Environment variables are the standard way to pass configuration into programs without hardcoding values. Reading them is essential for writing scripts that behave differently across development, staging, and production environments, or that respect system-level settings.

Given Input: No input required. The value is read from the operating system environment.

Expected Output: The value of the PATH variable (a long colon-separated string on Unix or semicolon-separated on Windows).

▼ Hint
  • Use os.environ.get("PATH") to safely read the variable. Unlike os.environ["PATH"], the .get() method returns None instead of raising a KeyError if the variable is missing.
  • Pass a second argument to .get() as the fallback value: os.environ.get("PATH", "Not set").
  • On Unix systems, individual directories in PATH are separated by :. Use .split(":") to print each directory on its own line.
▼ Solution & Explanation
import os

path_value = os.environ.get("PATH", "PATH variable not set")
print("PATH:", path_value)Code language: Python (python)

Explanation:

  • os.environ: A dictionary-like object that maps environment variable names to their string values. It reflects the environment at the time the Python interpreter started.
  • os.environ.get("PATH", "PATH variable not set"): The .get(key, default) pattern is the safest way to read an environment variable. If PATH is not defined, the second argument is returned instead of raising an exception.
  • Preferred over os.environ["PATH"]: Direct key access raises a KeyError if the variable is absent. Using .get() keeps the script robust, especially for optional or custom environment variables that may not always be set.

Exercise 12: Set an Environment Variable

Problem Statement: Write a Python program that sets a custom environment variable called APP_MODE to the value development, then reads it back and prints it.

Purpose: Setting environment variables at runtime lets scripts configure themselves or communicate settings to child processes. This is a common pattern in web frameworks, CLI tools, and test harnesses that need to switch between modes without changing source code.

Given Input: No external input. The variable is defined within the script.

Expected Output: APP_MODE is set to: development

▼ Hint
  • Set the variable using os.environ["APP_MODE"] = "development".
  • Read it back with os.environ.get("APP_MODE") to confirm it was stored correctly.
  • Remember that changes made to os.environ affect only the current process and its children – they do not persist in the shell after the script exits.
▼ Solution & Explanation
import os

# Set the environment variable
os.environ["APP_MODE"] = "development"

# Read it back
app_mode = os.environ.get("APP_MODE", "not set")
print(f"APP_MODE is set to: {app_mode}")Code language: Python (python)

Explanation:

  • os.environ["APP_MODE"] = "development": Adds or updates the key APP_MODE in the process environment. Both the key and value must be strings – passing an integer will raise a TypeError.
  • os.environ.get("APP_MODE", "not set"): Reads the variable back with a safe fallback. Because we just set it, this will return "development".
  • Scope of the change: The assignment modifies os.environ only for the lifetime of the current Python process. Any child processes launched via subprocess will inherit the updated environment, but the parent shell remains unchanged once the script exits.

Exercise 13: List All Environment Variables

Problem Statement: Write a Python program that prints all currently available environment variables, displaying each name and its value on a separate line in a readable format.

Purpose: Inspecting the full environment is helpful when debugging configuration issues, auditing what a script can see at runtime, or exploring a new system. This exercise also reinforces how to iterate over a dictionary-like object.

Given Input: No input required. The data is read from the live process environment.

Expected Output: A list of all environment variable names and values, one per line (output varies by system).

▼ Hint
  • os.environ behaves like a regular Python dictionary, so you can call .items() on it to get key-value pairs.
  • Use a for key, value in os.environ.items(): loop to iterate and print each pair.
  • Wrap the iteration in sorted(os.environ.items()) to print variables in alphabetical order for easier reading.
▼ Solution & Explanation
import os

for key, value in sorted(os.environ.items()):
    print(f"{key} = {value}")Code language: Python (python)

Explanation:

  • os.environ.items(): Returns all key-value pairs from the environment as an iterable of tuples, identical in behaviour to calling .items() on a standard Python dict.
  • sorted(...): Wrapping the iterable in sorted() arranges the variables alphabetically by key, making the output easier to scan compared to the arbitrary insertion order of the raw environment.
  • Privacy note: The environment may contain sensitive values such as API keys or passwords. Be careful not to log or display the full environment output in shared or production contexts.

Exercise 14: Get Current Process ID

Problem Statement: Write a Python program that retrieves and prints the process ID (PID) of the currently running Python script.

Purpose: The process ID uniquely identifies a running program on the operating system. It is useful in logging, debugging multi-process applications, creating unique temporary filenames, and communicating between processes. This exercise introduces basic process introspection using the os module.

Given Input: No input required. The PID is provided by the operating system.

Expected Output: Current Process ID: 12345 (the actual number will vary each time the script runs)

▼ Hint
  • Use os.getpid() to retrieve the PID of the current process as an integer.
  • Use os.getppid() to also retrieve the parent process ID as a bonus exercise.
▼ Solution & Explanation
import os

pid = os.getpid()
ppid = os.getppid()

print(f"Current Process ID: {pid}")
print(f"Parent Process ID: {ppid}")Code language: Python (python)

Explanation:

  • os.getpid(): Returns the integer process ID assigned by the OS to the current Python interpreter process. Each time the script runs, the OS assigns a different PID.
  • os.getppid(): Returns the PID of the parent process – typically the shell or terminal that launched the script. This is useful when working with process trees or verifying that a subprocess was spawned by the expected parent.
  • Practical use: PIDs are commonly embedded in log messages (f"[PID {os.getpid()}] Task started") to distinguish output from concurrent processes running the same script in parallel.

Exercise 15: Run a Shell Command

Problem Statement: Write a Python program that runs a shell command using os.system() and prints the exit code returned by the command.

Purpose: Running shell commands from within Python is a common requirement in automation scripts, build tools, and system administration utilities. This exercise introduces os.system() as the simplest way to invoke a command and inspect whether it succeeded or failed.

Given Input: No external input required. The command is hardcoded in the script.

Expected Output: The output of the shell command printed to the terminal, followed by Exit code: 0

▼ Hint
  • Use os.system("command") where the argument is a shell command string such as "ls" on Unix or "dir" on Windows.
  • os.system() returns the exit code of the command: 0 means success, any non-zero value indicates an error.
  • To make the script cross-platform, detect the OS first using sys.platform and choose the appropriate command accordingly.
▼ Solution & Explanation
import os
import sys

# Choose command based on OS
if sys.platform == "win32":
    command = "dir"
else:
    command = "ls"

exit_code = os.system(command)
print(f"Exit code: {exit_code}")Code language: Python (python)

Explanation:

  • os.system(command): Passes the command string to the operating system’s default shell and executes it. The output is printed directly to the terminal – it is not captured or returned as a Python value.
  • exit_code: The integer return value of os.system() is the command’s exit status. A value of 0 conventionally means the command completed without errors, while any non-zero value signals a failure.
  • Limitation: os.system() does not capture the command’s output into a Python variable. For that use case, prefer the subprocess module, specifically subprocess.run(command, capture_output=True, text=True).

Exercise 16: Walk a Directory Tree

Problem Statement: Write a Python program that recursively lists all files in a directory and its subdirectories, printing the full path of each file found.

Purpose: Traversing an entire directory tree is essential for tasks such as bulk file processing, searching for specific files, calculating total disk usage, and building file indexing tools. os.walk() handles all the recursion automatically, making it far simpler than writing your own recursive function.

Given Input: A sample directory tree created in the script: walk_demo/ with two subdirectories each containing a text file.

Expected Output: Full path of every file found inside the directory tree, one per line.

▼ Hint
  • os.walk(top) yields a three-element tuple on each iteration: (dirpath, dirnames, filenames).
  • Use os.path.join(dirpath, filename) inside the loop to build the full path to each file.
  • Pass topdown=False to os.walk() if you need to process deeper directories before their parents.
▼ Solution & Explanation
import os

# Create a sample directory tree for testing
os.makedirs("walk_demo/subdir_a", exist_ok=True)
os.makedirs("walk_demo/subdir_b", exist_ok=True)

with open("walk_demo/subdir_a/file1.txt", "w") as f:
    f.write("file one")
with open("walk_demo/subdir_b/file2.txt", "w") as f:
    f.write("file two")
with open("walk_demo/root_file.txt", "w") as f:
    f.write("root file")

# Walk the directory tree
for dirpath, dirnames, filenames in os.walk("walk_demo"):
    for filename in filenames:
        full_path = os.path.join(dirpath, filename)
        print(full_path)Code language: Python (python)

Explanation:

  • os.walk("walk_demo"): Returns a generator that traverses the directory tree rooted at the given path. On each step it yields a tuple of: the current directory path, a list of subdirectory names within it, and a list of filenames within it.
  • dirpath, dirnames, filenames: Unpacking the tuple into named variables makes the loop body clear. dirnames can be modified in-place during iteration to prune branches you want to skip.
  • os.path.join(dirpath, filename): Combines the current directory path with each filename to produce the complete, usable file path. Never concatenate paths with string addition, as it breaks on Windows where the separator is \.

Exercise 17: Join Paths Safely

Problem Statement: Write a Python program that constructs a file path from separate components using os.path.join() and prints the resulting path.

Purpose: Hardcoding path separators like / or \ makes scripts brittle and platform-specific. Using os.path.join() is the correct, portable approach that automatically uses the right separator for the operating system the script runs on.

Given Input: base = "projects", subfolder = "python_exercises", filename = "solution.py"

Expected Output: projects/python_exercises/solution.py (on Unix) or projects\python_exercises\solution.py (on Windows)

▼ Hint
  • Pass all path components as separate arguments to os.path.join() – it accepts any number of arguments.
  • If any component is an absolute path (starts with / on Unix or a drive letter on Windows), all previous components are discarded. This is a common source of bugs to be aware of.
  • Combine os.path.join() with os.path.abspath() to get the full absolute path from the result.
▼ Solution & Explanation
import os

base = "projects"
subfolder = "python_exercises"
filename = "solution.py"

full_path = os.path.join(base, subfolder, filename)
print("Joined path:", full_path)

# Bonus: get the absolute version of the path
abs_path = os.path.abspath(full_path)
print("Absolute path:", abs_path)Code language: Python (python)

Explanation:

  • os.path.join(base, subfolder, filename): Concatenates the path components using the correct OS separator. On Unix the result is projects/python_exercises/solution.py; on Windows it is projects\python_exercises\solution.py.
  • Absolute path override rule: If any argument passed to os.path.join() is an absolute path, all components before it are dropped. For example, os.path.join("home", "/etc", "config") returns /etc/config, not home/etc/config.
  • os.path.abspath(full_path): Resolves the joined relative path against the current working directory to produce a complete absolute path. This is useful when you need to pass a definitive path to other functions or display it in logs.

Exercise 18: Get Absolute Path

Problem Statement: Write a Python program that takes a relative file path and converts it to its full absolute path.

Purpose: Relative paths depend on the current working directory, which can change during a script’s execution. Converting to an absolute path early on locks in the location and prevents hard-to-debug errors when functions change directories mid-run or when paths are passed to other modules.

Given Input: relative_path = "data/report.csv"

Expected Output: A full absolute path such as /home/user/projects/data/report.csv (varies by system and working directory)

▼ Hint
  • Use os.path.abspath(path) to resolve a relative path into its full absolute form based on the current working directory.
  • Use os.path.dirname(abs_path) to extract just the directory portion of the resolved path.
  • Use os.path.basename(abs_path) to extract just the filename from the resolved path.
▼ Solution & Explanation
import os

relative_path = "data/report.csv"

abs_path = os.path.abspath(relative_path)
directory = os.path.dirname(abs_path)
filename = os.path.basename(abs_path)

print("Absolute path:", abs_path)
print("Directory    :", directory)
print("Filename     :", filename)Code language: Python (python)

Explanation:

  • os.path.abspath(relative_path): Resolves the given relative path by prepending the current working directory. It also normalises any . or .. components in the path, so "data/../data/report.csv" becomes a clean absolute path.
  • os.path.dirname(abs_path): Returns everything up to but not including the last path component. For a file path, this gives the containing directory.
  • os.path.basename(abs_path): Returns only the final component of the path – the filename in this case. Together, dirname and basename let you split any path into its folder and file parts without string manipulation.

Exercise 19: Print Python Version

Problem Statement: Write a Python program that displays the current Python version in two formats: as a human-readable string and as a structured named tuple with individual version components.

Purpose: Knowing the Python version at runtime is essential for writing scripts that conditionally use features only available in certain versions. It is also a standard first line of defence when debugging environment issues across different machines or deployment targets.

Given Input: No input required. The version is provided by the Python interpreter.

Expected Output: Python version: 3.11.4 (main, ...) and Major: 3 Minor: 11 Micro: 4 (values vary by installation)

▼ Hint
  • Use sys.version to get the full version string including build date and compiler info.
  • Use sys.version_info to access individual components like sys.version_info.major, .minor, and .micro.
▼ Solution & Explanation
import sys

print("Python version:", sys.version)
print(f"Major: {sys.version_info.major}  "
      f"Minor: {sys.version_info.minor}  "
      f"Micro: {sys.version_info.micro}")Code language: Python (python)

Explanation:

  • sys.version: A plain string containing the full Python version along with build metadata such as the compile date and compiler name. It is useful for display and logging but awkward to parse programmatically.
  • sys.version_info: A named tuple with fields major, minor, micro, releaselevel, and serial. Accessing individual fields makes version comparisons clean and readable, for example: if sys.version_info.major < 3: raise SystemExit("Python 3 required").
  • Version guarding: Always use sys.version_info for conditional logic rather than parsing sys.version as a string, since the string format can vary slightly across platforms and builds.

Exercise 20: Read Command-Line Arguments

Problem Statement: Write a Python program that reads arguments passed to it from the command line and prints each argument with its index position.

Purpose: Command-line arguments are the primary way to pass inputs to standalone scripts without hardcoding values or using interactive prompts. This exercise introduces sys.argv, which is the foundation for building CLI tools, utility scripts, and programs that integrate into shell pipelines.

Given Input: Run the script from the terminal as: python solution.py hello world 42

Expected Output: Each argument printed with its index, starting with the script name at index 0.

▼ Hint
  • sys.argv is a list where index 0 is always the script filename, and indices 1 onward are the arguments passed by the user.
  • Use enumerate(sys.argv) inside a for loop to iterate with both the index and the value.
  • All values in sys.argv are strings. Convert them explicitly if you need a number: int(sys.argv[1]).
▼ Solution & Explanation
import sys

print(f"Total arguments: {len(sys.argv)}")
print("Arguments received:")

for index, arg in enumerate(sys.argv):
    print(f"  [{index}] {arg}")Code language: Python (python)

Explanation:

  • sys.argv: A list of strings populated by the Python interpreter before the script runs. The first element (sys.argv[0]) is always the script name or path, making the actual user-supplied arguments start at index 1.
  • len(sys.argv): Gives the total count of all arguments including the script name. Checking this before accessing sys.argv[1] prevents an IndexError when the user runs the script without providing any arguments.
  • enumerate(sys.argv): Yields each argument paired with its position index, removing the need for a manual counter variable and making the output self-documenting.

Exercise 21: Exit a Program

Problem Statement: Write a Python program that checks whether a required command-line argument is provided and exits gracefully with a descriptive error message if it is missing.

Purpose: Controlled program termination is a sign of well-written scripts. Rather than letting a program crash with a cryptic traceback, sys.exit() lets you stop execution cleanly, communicate the reason to the user, and signal success or failure to the calling shell or process manager.

Given Input: Run without arguments (python solution.py) to trigger the exit, or with one argument (python solution.py Alice) to proceed normally.

Expected Output: Error: Please provide a name as an argument. followed by exit, or Hello, Alice! if the argument is present.

▼ Hint
  • Check len(sys.argv) < 2 to detect a missing argument, since sys.argv[0] is always the script name.
  • Call sys.exit("Error message") to print a message to stderr and terminate with exit code 1.
  • Pass an integer to sys.exit() to set a specific exit code: sys.exit(0) for success, sys.exit(1) for general errors.
▼ Solution & Explanation
import sys
if len(sys.argv) < 2:
    sys.exit("Error: Please provide a name as an argument.")
name = sys.argv[1]
print(f"Hello, {name}!")Code language: Python (python)

Explanation:

  • len(sys.argv) < 2: Since sys.argv[0] is always the script name, a length less than 2 means no user-supplied arguments were given. This guard must come before any attempt to access sys.argv[1] to avoid an IndexError.
  • sys.exit("Error: ..."): When called with a string argument, Python prints that string to stderr and exits the process with code 1. This signals failure to the calling shell, which is important for scripts used in automated pipelines.
  • Exit codes matter: A shell script or CI pipeline checks the exit code of each command. Using sys.exit(0) for success and sys.exit(1) (or a non-zero value) for failure makes your script a well-behaved participant in larger automated workflows.

Exercise 22: Get Platform Info

Problem Statement: Write a Python program that identifies the current operating system platform and prints a human-readable description of it.

Purpose: Writing cross-platform scripts requires knowing which OS the code is running on so that platform-specific behaviour – such as choosing the right shell command, file separator, or config path – can be handled correctly. This exercise introduces the two most common ways to detect the platform at runtime.

Given Input: No input required. The platform is detected from the runtime environment.

Expected Output: Platform: linux and Detailed platform: Linux-5.15.0-x86_64 (values vary by system)

▼ Hint
  • Use sys.platform for a short identifier: "linux", "darwin" (macOS), or "win32" (Windows).
  • Use platform.platform() from the built-in platform module for a more detailed description including OS version and architecture.
  • Use platform.system() to get just the OS name as a clean string: "Linux", "Darwin", or "Windows".
▼ Solution & Explanation
import sys
import platform

print("sys.platform       :", sys.platform)
print("platform.system()  :", platform.system())
print("platform.platform():", platform.platform())
print("platform.machine() :", platform.machine())Code language: Python (python)

Explanation:

  • sys.platform: A short lowercase string set by the Python interpreter at startup. The most common values are "linux" for Linux, "darwin" for macOS, and "win32" for all versions of Windows including 64-bit. It is the simplest way to branch platform-specific logic.
  • platform.system(): Returns a cleaner, title-cased OS name such as "Linux", "Darwin", or "Windows" without the extra build detail. It is easier to read in output intended for end users.
  • platform.platform(): Returns a full descriptive string that includes the OS name, version, and hardware architecture. It is most useful in diagnostic logs and bug reports where full environment detail is needed.
  • platform.machine(): Returns the hardware architecture identifier such as "x86_64" or "arm64", which is useful when building or distributing architecture-specific packages.

Exercise 23: Inspect sys.path

Problem Statement: Write a Python program that prints all the directories Python searches when looking for modules to import, displaying each directory on a separate line.

Purpose: Understanding sys.path is essential for diagnosing ModuleNotFoundError problems, understanding how Python resolves imports, and knowing where to place custom modules so they can be imported without any configuration. This exercise builds a mental model of how Python’s import system works.

Given Input: No input required. The path list is maintained by the Python interpreter.

Expected Output: A numbered list of all directories in the module search path (output varies by system and virtual environment).

▼ Hint
  • sys.path is a regular Python list of strings, so you can iterate over it with a for loop or use enumerate() to add index numbers.
  • The first entry (sys.path[0]) is typically an empty string "" or the script’s own directory, meaning Python checks the current directory first.
  • You can also print the length with len(sys.path) to see how many locations are being searched.
▼ Solution & Explanation
import sys

print(f"Total search paths: {len(sys.path)}\n")

for index, path in enumerate(sys.path):
    print(f"[{index}] {path if path else '(current directory)'}")Code language: Python (python)

Explanation:

  • sys.path: A list of directory strings that Python scans in order when an import statement is encountered. The first matching module found wins. This list is assembled from the script’s directory, the PYTHONPATH environment variable, and installation-specific defaults.
  • Empty string entry: An empty string "" at any position in sys.path represents the current working directory. The conditional path if path else '(current directory)' makes this explicit in the output rather than printing a blank line.
  • Order matters: Python imports the first module it finds as it walks the list from index 0 onward. If two directories both contain a module with the same name, the one in the lower-indexed directory takes precedence – a common source of shadowing bugs.

Exercise 24: Add to sys.path

Problem Statement: Write a Python program that dynamically adds a custom directory to sys.path so that modules stored in that directory can be imported without installing them as packages.

Purpose: There are situations where you need to import a module from a non-standard location – for example, a shared utilities folder, a sibling project directory, or a path determined at runtime. Modifying sys.path programmatically is the direct way to achieve this without changing environment variables or restructuring the project.

Given Input: A custom directory path custom_modules containing a simple Python file greet.py (both created in the script).

Expected Output: Hello from custom module!

▼ Hint
  • Use sys.path.insert(0, directory_path) to add your directory at the front of the search list so it is checked before any other location.
  • Use os.path.abspath() when constructing the path to insert, to avoid issues with relative paths changing meaning if the working directory changes later.
  • Check that the path is not already in sys.path before inserting to avoid duplicates: if directory_path not in sys.path.
▼ Solution & Explanation
import sys
import os

# Create a custom module directory and a simple module inside it
custom_dir = os.path.abspath("custom_modules")
os.makedirs(custom_dir, exist_ok=True)

with open(os.path.join(custom_dir, "greet.py"), "w") as f:
    f.write('def hello():\n    print("Hello from custom module!")\n')

# Add the directory to sys.path if not already present
if custom_dir not in sys.path:
    sys.path.insert(0, custom_dir)

# Now import and use the module
import greet
greet.hello()Code language: Python (python)

Explanation:

  • sys.path.insert(0, custom_dir): Inserts the custom directory at position 0 so it is the first location Python checks during any subsequent import. Using append() instead would add it to the end, meaning it would only be consulted after all standard library and site-packages locations.
  • os.path.abspath(custom_dir): Converts the relative directory name into a full absolute path. This ensures the entry in sys.path remains valid even if the working directory changes later in the same script.
  • Duplicate check: The if custom_dir not in sys.path guard prevents the same directory from being added multiple times if the script or function is called more than once, keeping sys.path clean.

Exercise 25: Get Recursion Limit

Problem Statement: Write a Python program that retrieves and prints the maximum recursion depth allowed by the current Python interpreter.

Purpose: Python limits how deeply functions can call themselves to prevent a stack overflow from consuming all available memory. Knowing this limit helps you understand why deeply recursive algorithms fail with a RecursionError and prepares you for the next exercise where the limit is adjusted.

Given Input: No input required.

Expected Output: Current recursion limit: 1000 (the default on most Python installations)

▼ Hint
  • Use sys.getrecursionlimit() to retrieve the current maximum recursion depth as an integer.
  • Write a simple recursive function that counts down from a number to demonstrate what happens as the call stack grows toward the limit.
▼ Solution & Explanation
import sys

limit = sys.getrecursionlimit()
print(f"Current recursion limit: {limit}")

# Demonstrate recursion depth with a simple countdown
def countdown(n):
    if n == 0:
        return "Done"
    return countdown(n - 1)

print(countdown(50))
print("Recursion test with depth 50: passed")Code language: Python (python)

Explanation:

  • sys.getrecursionlimit(): Returns the current maximum depth of the Python interpreter call stack as an integer. The default value on most systems is 1000, meaning a chain of more than 1000 nested function calls will raise a RecursionError.
  • What counts as a level: Every function call – including calls made indirectly through other functions – increments the call stack depth by one. A recursive function that calls itself 1001 times will exceed the default limit on the 1001st call.
  • Practical context: Many real-world recursive algorithms such as tree traversal, parsing nested structures, or depth-first search can easily exceed 1000 levels on large inputs. In those cases the limit must either be raised or the algorithm rewritten iteratively.

Exercise 26: Change Recursion Limit

Problem Statement: Write a Python program that increases the recursion limit and then tests it by running a recursive function that would fail under the default limit.

Purpose: Some legitimate algorithms – such as processing deeply nested JSON, traversing large trees, or implementing certain parsers – require a deeper call stack than Python’s default allows. This exercise shows how to raise the limit safely and why it should be done with care.

Given Input: No input required. The recursion depth is set within the script.

Expected Output: Old limit: 1000, New limit: 2000, and Recursion test with depth 1500: passed

▼ Hint
  • Use sys.setrecursionlimit(n) to set a new maximum recursion depth before calling the recursive function.
  • Save the original limit with sys.getrecursionlimit() before changing it so you can restore it afterward if needed.
  • Be cautious: setting the limit too high can cause a genuine stack overflow and crash the Python interpreter rather than raising a catchable RecursionError.
▼ Solution & Explanation
import sys

old_limit = sys.getrecursionlimit()
print(f"Old limit: {old_limit}")

sys.setrecursionlimit(2000)
print(f"New limit: {sys.getrecursionlimit()}")

def deep_recurse(n):
    if n == 0:
        return "Done"
    return deep_recurse(n - 1)

result = deep_recurse(1500)
print(f"Recursion test with depth 1500: passed")

# Restore original limit
sys.setrecursionlimit(old_limit)Code language: Python (python)

Explanation:

  • sys.setrecursionlimit(2000): Raises the maximum allowed call stack depth to 2000, allowing the subsequent recursive call with depth 1500 to complete without raising a RecursionError. The new limit takes effect immediately for all subsequent calls in the process.
  • Restoring the original limit: Saving and restoring the old limit via sys.setrecursionlimit(old_limit) is good practice, especially in libraries or test suites where side effects on global interpreter state should be minimised.
  • Safety ceiling: Setting the limit to an extremely large value such as 10**6 can cause a hard crash (segmentation fault) because the OS-level thread stack is exhausted before Python can raise a clean RecursionError. Stay within a few thousand unless you have a specific, tested need for more.

Exercise 27: Script Info Logger

Problem Statement: Write a Python program that collects information about itself – its filename, the current working directory, and the OS platform – and writes all of it to a log file called script_info.log.

Purpose: Logging runtime context is a fundamental practice in production scripts and scheduled jobs. When something goes wrong, a log that captures where the script ran, on what platform, and under which filename gives you the starting point for diagnosis. This exercise combines sys and os together for the first time in a practical output task.

Given Input: No input required. All values are derived from the runtime environment.

Expected Output: A file script_info.log created in the current directory, and the log contents printed to the terminal.

▼ Hint
  • Use sys.argv[0] to get the script filename, os.getcwd() for the current directory, and sys.platform for the OS identifier.
  • Open the log file with open("script_info.log", "w") and write each piece of information on a new line.
  • Use sys.stdout.write() as an alternative to print() to write directly to standard output, reinforcing awareness of the underlying stream.
▼ Solution & Explanation
import os
import sys

script_name = sys.argv[0]
current_dir = os.getcwd()
platform    = sys.platform
python_ver  = sys.version.split()[0]

log_lines = [
    f"Script   : {script_name}",
    f"Directory: {current_dir}",
    f"Platform : {platform}",
    f"Python   : {python_ver}",
]

log_path = "script_info.log"

with open(log_path, "w") as log_file:
    for line in log_lines:
        log_file.write(line + "\n")
        sys.stdout.write(line + "\n")

print(f"\nLog written to: {os.path.abspath(log_path)}")Code language: Python (python)

Explanation:

  • sys.argv[0]: Always holds the name or path of the script itself as provided to the interpreter. In an interactive session this is an empty string or a special identifier, but when running a saved script it reflects the actual filename.
  • sys.version.split()[0]: Extracts just the version number (e.g. 3.11.4) from the full version string, discarding the build date and compiler detail that follow it.
  • sys.stdout.write(line + "\n"): Writes directly to standard output without the automatic newline and space-separated argument behaviour of print(). It makes the parallel between writing to the file and writing to the terminal explicit, highlighting that both are just file-like streams.

Exercise 28: Directory Size Calculator

Problem Statement: Write a Python program that calculates the total size of all files in a directory tree and displays the result in bytes, kilobytes, and megabytes.

Purpose: Calculating disk usage is a practical task in backup tools, storage monitoring scripts, and deployment pipelines. This exercise combines os.walk() for recursion with os.path.getsize() for per-file measurement, reinforcing how the two functions work together.

Given Input: A sample directory tree size_demo/ created in the script with a few files of varying sizes.

Expected Output: Total size printed in bytes, KB, and MB (exact values depend on the test files created).

▼ Hint
  • Use os.walk(directory) to traverse all subdirectories and os.path.getsize() on each file to accumulate the total.
  • Build the full file path inside the loop with os.path.join(dirpath, filename) before passing it to getsize().
  • Divide the total byte count by 1024 for KB and by 1024 ** 2 for MB, then format with two decimal places using :.2f.
▼ Solution & Explanation
import os

# Create a sample directory tree with files for testing
os.makedirs("size_demo/docs", exist_ok=True)
os.makedirs("size_demo/data", exist_ok=True)

with open("size_demo/docs/readme.txt", "w") as f:
    f.write("A" * 1024)           # 1 KB of content

with open("size_demo/data/records.csv", "w") as f:
    f.write("B" * 2048)           # 2 KB of content

with open("size_demo/notes.txt", "w") as f:
    f.write("C" * 512)            # 0.5 KB of content

# Calculate total size
total_bytes = 0
for dirpath, dirnames, filenames in os.walk("size_demo"):
    for filename in filenames:
        full_path = os.path.join(dirpath, filename)
        total_bytes += os.path.getsize(full_path)

print(f"Total size: {total_bytes} bytes")
print(f"Total size: {total_bytes / 1024:.2f} KB")
print(f"Total size: {total_bytes / 1024 ** 2:.4f} MB")Code language: Python (python)

Explanation:

  • total_bytes += os.path.getsize(full_path): Accumulates the size of every file encountered during the walk into a running total. getsize() reads directly from filesystem metadata, so there is no need to open or read any file content.
  • os.path.join(dirpath, filename): Constructs the correct full path to each file within the loop. Passing just filename to getsize() would fail unless the file happened to be in the current working directory.
  • Unit conversion: Dividing by 1024 converts bytes to kibibytes (KB) and by 1024 ** 2 converts to mebibytes (MB). The :.2f format specifier rounds the float to two decimal places for a clean display.

Exercise 29: Environment Config Loader

Problem Statement: Write a Python program that simulates loading application configuration by reading multiple environment variables with fallback defaults, then prints a formatted summary of the configuration to standard output.

Purpose: Reading configuration from environment variables is the industry-standard approach for twelve-factor applications. It keeps secrets and environment-specific settings out of source code. This exercise combines os.environ.get() with sys.stdout to build a realistic config-loading pattern used in web apps, APIs, and CLI tools.

Given Input: Environment variables APP_HOST, APP_PORT, and APP_DEBUG – set within the script to simulate a configured environment.

Expected Output: A formatted configuration summary printed to stdout showing each key and its resolved value.

▼ Hint
  • Use os.environ.get("KEY", "default_value") for each setting so the script works even when variables are not set in the environment.
  • Store all config key-value pairs in a dictionary and iterate over it to print the summary, keeping the loading and display logic separate.
  • Use sys.stdout.write() instead of print() for at least part of the output to practise writing to the standard output stream directly.
▼ Solution & Explanation
import os
import sys
# Simulate setting environment variables for this session
os.environ["APP_HOST"]  = "127.0.0.1"
os.environ["APP_PORT"]  = "8080"
# APP_DEBUG is intentionally left unset to demonstrate the fallback
# Load config with defaults
config = {
    "APP_HOST":  os.environ.get("APP_HOST",  "localhost"),
    "APP_PORT":  os.environ.get("APP_PORT",  "5000"),
    "APP_DEBUG": os.environ.get("APP_DEBUG", "False"),
    "APP_ENV":   os.environ.get("APP_ENV",   "production"),
}
# Print summary via sys.stdout
sys.stdout.write("=== Application Configuration ===\n")
for key, value in config.items():
    sys.stdout.write(f"  {key:<12}: {value}\n")
sys.stdout.write("=================================\n")Code language: Python (python)

Explanation:

  • os.environ.get("KEY", "default"): Reads the environment variable named KEY and returns its string value if present, or the second argument as a fallback if it is not set. This pattern ensures the application always has a usable value for every setting regardless of the deployment environment.
  • Dictionary-based config: Storing all settings in a single config dict separates the loading step from the display and usage steps. This mirrors how configuration libraries such as dynaconf and python-decouple work internally.
  • sys.stdout.write(): Writes a string directly to the standard output stream. Unlike print(), it does not add a trailing newline automatically, giving you full control over line endings. The f"{key:<12}" format left-aligns the key in a field of 12 characters, producing a neatly aligned two-column layout.

Exercise 30: Recursive File Finder

Problem Statement: Write a Python program that accepts a file extension as a command-line argument and recursively searches the current directory tree for all files matching that extension, printing the full path of each match.

Purpose: This capstone exercise combines everything covered in the module: sys.argv for input, sys.exit() for validation, os.walk() for traversal, os.path.join() for path construction, and os.path.splitext() for extension matching. It mirrors a real-world utility script that you might use or build as part of a larger automation pipeline.

Given Input: Run as python solution.py .txt from the terminal. A sample directory tree with mixed file types is created by the script for testing.

Expected Output: Full paths of all .txt files found in the directory tree, followed by a count of matches.

▼ Hint
  • Use sys.exit() early if len(sys.argv) < 2 to inform the user how to provide the extension argument.
  • Normalise the extension with .lower() and ensure it starts with a dot so both txt and .txt are accepted as valid input.
  • Inside the os.walk() loop, use os.path.splitext(filename)[1].lower() to extract and compare each file’s extension.
▼ Solution & Explanation
import os
import sys
# Create a sample directory tree with mixed file types for testing
os.makedirs("search_demo/docs", exist_ok=True)
os.makedirs("search_demo/data", exist_ok=True)
for name in ["search_demo/docs/notes.txt",
             "search_demo/docs/readme.txt",
             "search_demo/data/records.csv",
             "search_demo/data/summary.txt",
             "search_demo/config.json"]:
    with open(name, "w") as f:
        f.write("sample content")
# Validate command-line argument
if len(sys.argv) < 2:
    sys.exit("Usage: python solution.py <extension>  e.g. python solution.py .txt")
# Normalise the extension
ext = sys.argv[1].lower()
if not ext.startswith("."):
    ext = "." + ext
# Search the directory tree
matches = []
for dirpath, dirnames, filenames in os.walk("search_demo"):
    for filename in filenames:
        if os.path.splitext(filename)[1].lower() == ext:
            matches.append(os.path.join(dirpath, filename))
# Display results
if matches:
    print(f"Files with extension '{ext}':")
    for path in matches:
        print(f"  {path}")
    print(f"\nTotal found: {len(matches)}")
else:
    print(f"No files with extension '{ext}' found.")Code language: Python (python)

Explanation:

  • sys.argv validation and normalisation: Checking len(sys.argv) < 2 before accessing sys.argv[1] prevents an IndexError. The dot-prefix check and .lower() call make the tool forgiving so users can pass either txt or .TXT and get the same result.
  • os.path.splitext(filename)[1].lower(): Extracts the extension from each filename and normalises its case before comparing. This prevents a mismatch between .TXT in the filename and .txt in the search term on case-sensitive filesystems.
  • Collecting into a list before printing: Appending matches to a list rather than printing inside the loop separates the search logic from the display logic. This makes it easy to extend the script later – for example, to sort the results, filter by size, or pass the list to another function.

Filed Under: Python, Python Exercises

Did you find this page helpful? Let others know about it. Sharing helps me continue to create free Python resources.

TweetF  sharein  shareP  Pin

About Vishal

I’m Vishal Hule, the Founder of PYnative.com. As a Python developer, I enjoy assisting students, developers, and learners. Follow me on Twitter.

Related Tutorial Topics:

Python Python Exercises

All Coding Exercises:

C Exercises
C++ Exercises
Python Exercises

Python Exercises and Quizzes

Free coding exercises and quizzes cover Python basics, data structure, data analytics, and more.

  • 15+ Topic-specific Exercises and Quizzes
  • Each Exercise contains 25+ questions
  • Each Quiz contains 25 MCQ
Exercises
Quizzes

Leave a Reply Cancel reply

your email address will NOT be published. all comments are moderated according to our comment policy.

Use <pre> tag for posting code. E.g. <pre> Your entire code </pre>

In: Python Python Exercises
TweetF  sharein  shareP  Pin

  Python Exercises

  • All Python Exercises
  • Basic Exercises for Beginners
  • Loop Exercises
  • Intermediate Python Exercises
  • Input and Output Exercises
  • Functions Exercises
  • String Exercises
  • List Exercises
  • Dictionary Exercises
  • Set Exercises
  • Tuple Exercises
  • Data Structure Exercises
  • Comprehensions Exercises
  • Collections Module Exercises
  • Date and Time Exercises
  • OOP Exercises
  • Exception Handling Exercises
  • Math and Statistics Exercises
  • File Handling Exercises
  • OS and Sys Module Exercises
  • Regex Exercises
  • Lambda & Functional Programming Exercises
  • Iterators & Generators Exercises
  • Itertools & Functools Exercises
  • Random Data Generation Exercises
  • NumPy Exercises
  • Pandas Exercises
  • Matplotlib Exercises
  • Python Database Exercises
  • Python JSON Exercises

 Explore Python

  • Python Tutorials
  • Python Exercises
  • Python Quizzes
  • Python Interview Q&A
  • Python Programs

All Python Topics

Python Basics Python Exercises Python Quizzes Python Interview Python File Handling Python OOP Python Date and Time Python Random Python Regex Python Pandas Python Databases Python MySQL Python PostgreSQL Python SQLite Python JSON

About PYnative

PYnative.com is for Python lovers. Here, You can get Tutorials, Exercises, and Quizzes to practice and improve your Python skills.

Follow Us

To get New Python Tutorials, Exercises, and Quizzes

  • Twitter
  • Facebook
  • Sitemap

Explore Python

  • Learn Python
  • Python Basics
  • Python Databases
  • Python Exercises
  • Python Quizzes
  • Online Python Code Editor
  • Python Tricks

Coding Exercises

  • C Exercises
  • C++ Exercises
  • Python Exercises

Legal Stuff

  • About Us
  • Contact Us

We use cookies to improve your experience. While using PYnative, you agree to have read and accepted our:

  • Terms Of Use
  • Privacy Policy
  • Cookie Policy

Copyright © 2018–2026 pynative.com