Python OS, Sys & Pathlib Guide
The os module provides a portable, platform-independent interface to interact with the underlying operating system (Windows, macOS, Linux):
- Environment Variables:
os.environ(a dictionary mapping OS environment keys likeAPI_KEY,PATH,USER). Always useos.getenv("KEY", "fallback")for safe access. - Working Directory:
os.getcwd()(get current directory),os.chdir(path)(change directory). - Directory Management:
os.mkdir(path)(create single folder),os.makedirs(path, exist_ok=True)(create nested directory trees safely). - Listing & Deleting:
os.listdir(path),os.remove(file),os.rmdir(empty_dir).
# Inspecting OS environment and directory state:
import os
print("Operating System Name:", os.name) # 'nt' for Windows, 'posix' for Linux/macOS
print("Current Working Directory:", os.getcwd())
# Safe environment variable lookup with getenv:
db_user = os.getenv("DB_USER", "default_admin")
print("Database User:", db_user)
# Inspecting directory contents:
dir_files = [f for f in os.listdir(".") if not f.startswith(".")]
print(f"Top 5 files in current directory: {dir_files[:5]}")
Never hardcode API secrets, database passwords, or private keys directly in source code. Load them dynamically from environment variables using os.getenv("SECRET_KEY").
The sys module provides access to variables and functions that interact directly with the CPython interpreter itself:
sys.argv: A list of command-line argument strings passed to the script during terminal invocation (wheresys.argv[0]is the script name).sys.exit([code]): Immediately terminates the Python process (exit code0signifies clean success, non-zero signifies an error).sys.version/sys.version_info: The exact Python version string and tuple.sys.platform: Identifies the OS platform ("win32","darwin"for macOS,"linux").sys.getsizeof(object): Returns the exact memory footprint of an object in bytes.
import sys
print(f"๐ Python Runtime Version: {sys.version.split()[0]}")
print(f"๐ป OS Platform Identifier: {sys.platform}")
print(f"๐ฅ Command-line Arguments (sys.argv): {sys.argv}")
# Inspecting memory size of different Python objects in bytes:
int_size = sys.getsizeof(100)
str_size = sys.getsizeof("Hello, World!")
list_size = sys.getsizeof([1, 2, 3, 4, 5])
print(f"\nMemory Footprint:")
print(f"โข Integer (100): {int_size} bytes")
print(f"โข String ('Hello..'): {str_size} bytes")
print(f"โข List ([1..5]): {list_size} bytes")
If you run python process.py input.csv --verbose in your terminal, sys.argv will contain ['process.py', 'input.csv', '--verbose'].
Historically, Python developers manipulated file paths as raw strings using os.path.join(). In modern Python 3.4+ (PEP 428), the standard approach is pathlib.Path, which treats file paths as rich, first-class Python objects with cross-platform slash (/) joining:
Path Object Methods:
path.exists(): ReturnsTrueif file or directory exists.path.is_file()/path.is_dir(): Type checks.path.name: Full filename ("report.csv").path.stem: Filename without extension ("report").path.suffix: File extension (".csv").path.read_text(encoding="utf-8"): Reads entire text file in one line!path.write_text(content, encoding="utf-8"): Writes string to file in one line!
from pathlib import Path
# 1. Building paths with the / operator:
data_folder = Path("my_project") / "data"
config_file = data_folder / "app_config.json"
print("Path Object:", config_file)
print("Filename (name):", config_file.name)
print("Filename stem: ", config_file.stem)
print("Extension: ", config_file.suffix)
print("Parent Folder: ", config_file.parent)
# 2. Writing and reading text files in ONE line with pathlib:
test_file = Path("demo_note.txt")
test_file.write_text("Hello from Python pathlib! ๐", encoding="utf-8")
file_content = test_file.read_text(encoding="utf-8")
print(f"\nRead file content: '{file_content}'")
# Clean up test file:
if test_file.exists():
test_file.unlink() # Delete file
print("Cleaned up demo_note.txt โ
")
pathlib automatically handles Windows backslashes (\) vs POSIX forward slashes (/) transparently without manual string manipulation.
Search and iterate through files matching pattern expressions using Globbing:
path.glob("*.py"): Finds matching files in the current folder.path.rglob("*.py"): Recursive Glob โ searches the current folder AND all nested sub-folders at any depth!
from pathlib import Path
current_dir = Path(".")
# Find all HTML files in current folder:
html_files = list(current_dir.glob("*.html"))
print(f"Found {len(html_files)} HTML files in current root.")
# Inspect first 3 files:
for f in html_files[:3]:
print(f"โข File: {f.name:25} | Size: {f.stat().st_size} bytes")
Path.glob() returns an efficient generator iterator, allowing you to stream millions of files without consuming gigabytes of RAM.
Never use string concatenation (+) or hardcoded backslashes for file paths. Hardcoded Windows paths like "folder\\file.txt" will crash on Linux/Docker servers. Always use pathlib.Path("folder") / "file.txt".
Use pathlib to construct a path "logs/2026/app.log", print its parent directories, and check if it exists.
from pathlib import Path
log_path = Path("logs") / "2026" / "app.log"
print("Constructed Path:", log_path)
print("Parent Directory:", log_path.parent)
print("File Extension: ", log_path.suffix)
print("Does file exist? ", log_path.exists())
Q Why should I prefer pathlib over os.path in modern Python?
pathlib provides an intuitive, object-oriented API where paths are rich objects with built-in methods (.read_text(), .write_text(), .exists(), .glob()), eliminating cumbersome nested os.path.join() boilerplate.
Q What does sys.exit(0) vs sys.exit(1) mean in command-line scripts?
In standard Unix and Windows conventions, exit code 0 indicates normal, successful execution. Any non-zero integer (like 1) indicates an error or abnormal termination to the calling shell/CI pipeline.
Q How do I safely create nested folders without crashing if they exist?
Use Path("my/deep/folder").mkdir(parents=True, exist_ok=True) or os.makedirs("my/deep/folder", exist_ok=True).