Project Setup
First, let's set up our projects. We'll create a simple CLI tool that counts lines, words, and characters in a file (like wc).
CLI Application Setup
Python
# Python: Using Click for CLI
# File: wc.py
import click
import sys
from pathlib import Path
@click.command()
@click.argument('file', type=click.Path(exists=True))
@click.option('--lines/--no-lines', '-l', default=True, help='Count lines')
@click.option('--words/--no-words', '-w', default=True, help='Count words')
@click.option('--chars/--no-chars', '-c', default=False, help='Count characters')
def wc(file, lines, words, chars):
    """A simple word count program."""
    try:
        content = Path(file).read_text()
        counts = {}
        
        if lines:
            counts['lines'] = len(content.splitlines())
        if words:
            counts['words'] = len(content.split())
        if chars:
            counts['chars'] = len(content)
            
        click.echo(f"{file}")
        for name, count in counts.items():
            click.echo(f"  {name}: {count}")
            
    except Exception as e:
        click.echo(f"Error: {e}", err=True)
        sys.exit(1)
if __name__ == '__main__':
    wc()Rust
// Rust: Using clap for CLI
// File: src/main.rs
use clap::Parser;
use std::fs;
use std::path::PathBuf;
/// A simple word count program
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
    /// Input file
    file: PathBuf,
    /// Count lines
    #[arg(short, long, default_value_t = true)]
    lines: bool,
    /// Count words
    #[arg(short, long, default_value_t = true)]
    words: bool,
    /// Count characters
    #[arg(short, long, default_value_t = false)]
    chars: bool,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let args = Args::parse();
    
    let content = fs::read_to_string(&args.file)?;
    let mut counts = std::collections::HashMap::new();
    
    if args.lines {
        counts.insert("lines", content.lines().count());
    }
    if args.words {
        counts.insert("words", content.split_whitespace().count());
    }
    if args.chars {
        counts.insert("chars", content.chars().count());
    }
    
    println!("{}", args.file.display());
    for (name, count) in counts {
        println!("  {}: {}", name, count);
    }
    
    Ok(())
}Dependencies
Both languages use package/dependency management, but they work differently:
Dependency Management
Python
# Python: requirements.txt or pyproject.toml
# Using pyproject.toml (modern approach)
[build-system]
requires = ["setuptools>=42"]
build-backend = "setuptools.build_meta"
[project]
name = "py-wc"
version = "0.1.0"
description = "A word count program in Python"
requires-python = ">=3.8"
dependencies = [
    "click>=8.0.0",
]
[project.scripts]
py-wc = "wc:wc"Rust
// Rust: Cargo.toml
[package]
name = "rust-wc"
version = "0.1.0"
edition = "2021"
description = "A word count program in Rust"
[dependencies]
clap = { version = "4.0", features = ["derive"] }Building and Running
Let's see how to build and run our applications:
Building and Running
Python
# Install in development mode
$ pip install -e .
# Run the script
$ py-wc --help
Usage: py-wc [OPTIONS] FILE
  A simple word count program.
Arguments:
  FILE  [required]
Options:
  -l, --lines / --no-lines  Count lines  [default: True]
  -w, --words / --no-words  Count words  [default: True]
  -c, --chars / --no-chars  Count characters  [default: False]
  --help                    Show this message and exit.Rust
# Build in debug mode (fast compile, slower runtime)
$ cargo build
# Build in release mode (slower compile, faster runtime)
$ cargo build --release
# Run directly with Cargo
$ cargo run -- --help
A simple word count program
Usage: rust-wc [OPTIONS] <FILE>
Arguments:
  <FILE>  Input file
Options:
  -l, --lines  Count lines [default: true]
  -w, --words  Count words [default: true]
  -c, --chars  Count characters [default: false]
  -h, --help   Print help
  -V, --version    Print versionError Handling
Both languages handle errors, but Rust's approach is more explicit:
Error Handling
Python
# Python: Exceptions
try:
    with open("nonexistent.txt") as f:
        content = f.read()
except FileNotFoundError as e:
    print(f"Error: {e}", file=sys.stderr)
    sys.exit(1)
except Exception as e:
    print(f"Unexpected error: {e}", file=sys.stderr)
    sys.exit(1)Rust
// Rust: Result type
use std::fs::File;
use std::io::Read;
fn read_file(path: &str) -> Result<String, Box<dyn std::error::Error>> {
    let mut file = File::open(path)?;
    let mut content = String::new();
    file.read_to_string(&mut content)?;
    Ok(content)
}
// Usage:
match read_file("nonexistent.txt") {
    Ok(content) => println!("File content: {}", content),
    Err(e) => eprintln!("Error reading file: {}", e),
}Testing
Both languages have built-in testing support:
Testing
Python
# test_wc.py
import pytest
from wc import wc
from click.testing import CliRunner
def test_wc_lines():
    runner = CliRunner()
    result = runner.invoke(wc, ["--no-words", "--no-chars", "test.txt"])
    assert "lines: 10" in result.output
    assert result.exit_code == 0Rust
// tests/wc_test.rs
#[test]
fn test_count_lines() {
    let content = "Hello
world
";
    let args = Args {
        file: "test.txt".into(),
        lines: true,
        words: false,
        chars: false,
    };
    
    // Test logic here
    assert_eq!(count_lines(&content), 2);
}
// In Cargo.toml:
// [[test]]
// name = "wc_test"
// path = "tests/wc_test.rs"Packaging and Distribution
Packaging for distribution works differently in both ecosystems:
Packaging and Distribution
Python
# Python: Using setuptools and PyPI
# Build distribution
$ python -m build
# Upload to PyPI
$ twine upload dist/*
# Install from PyPI
$ pip install py-wcRust
// Rust: Using Cargo and crates.io
# Build for release
$ cargo build --release
# The binary is in target/release/rust-wc
# Publish to crates.io
$ cargo publish
# Install globally
$ cargo install rust-wcPerformance Comparison
Performance Note
Rust's compiled nature gives it a significant performance advantage:
- Startup time: Rust is typically 10-100x faster than Python
 - Memory usage: Rust uses about half the memory of Python
 - CPU usage: Rust is often 2-10x faster for CPU-bound tasks
 - Binary size: Rust produces standalone binaries (larger but self-contained)
 
Key Takeaways
- Development speed: Python is often quicker for prototyping
 - Performance: Rust provides better performance and lower resource usage
 - Error handling: Rust's explicit error handling catches more issues at compile time
 - Distribution: Rust produces standalone binaries, Python requires an interpreter
 - Learning curve: Rust has a steeper learning curve but offers more control
 
When to Choose Which?
Choose Python When:
- Rapid prototyping is needed
 - Performance is not critical
 - You need extensive data science libraries
 - Team is more familiar with Python
 
Choose Rust When:
- Performance is critical
 - Memory safety is important
 - You want to avoid runtime errors
 - Building system-level tools