Skip to content

Generators

Generators and Iterators

Python

  • Generators: Use yield for lazy evaluation.
  • Iterators: Objects that implement __iter__ and __next__.
1
2
3
4
5
6
7
8
9
def count_up_to(max):
    count = 1
    while count <= max:
        yield count
        count += 1

gen = count_up_to(5)
for i in gen:
    print(i)

Rust

  • Iterators: Core part of Rust, implemented via the Iterator trait.
  • No direct equivalent to yield: But can achieve similar functionality with iterator adaptors or by implementing Iterator trait.
struct CountUpTo {
    count: u32,
    max: u32,
}

impl Iterator for CountUpTo {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.count <= self.max {
            let ret = self.count;
            self.count += 1;
            Some(ret)
        } else {
            None
        }
    }
}

let counter = CountUpTo { count: 1, max: 5 };
for i in counter {
    println!("{}", i);
}

Context Managers

Python

  • Context Managers: Use with statement to automatically manage resources.
with open('file.txt', 'r') as f:
    file_contents = f.read()

Rust

  • RAII (Resource Acquisition Is Initialization): Resources are released when the variable goes out of scope, similar to context managers. Uses the Drop trait.
1
2
3
4
{
    let f = File::open("file.txt").expect("Unable to open file");
    // Use file
} // `f` goes out of scope and is automatically closed here

Asynchronous Programming

Python

  • Async/Await: Python 3.5+ supports async and await for asynchronous programming.
import asyncio

async def fetch_data():
    await asyncio.sleep(2)
    return {'data': 1}

async def main():
    result = await fetch_data()
    print(result)

asyncio.run(main())

Rust

  • Async/Await: Rust also supports async and await, often used with tokio or async-std.
use tokio;

#[tokio::main]
async fn main() {
    let data = fetch_data().await;
    println!("{:?}", data);
}

async fn fetch_data() -> Result<u32, &'static str> {
    // Simulate an async operation
    tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
    Ok(1)
}

Concurrency

Python

  • Threading and Multiprocessing: Due to GIL, multiprocessing is often used for CPU-bound tasks.
from multiprocessing import Process

def process_data(data):
    # Process data
    pass

if __name__ == "__main__":
    p = Process(target=process_data, args=(data,))
    p.start()
    p.join()

Rust

  • Concurrency: Rust's ownership and type system allow for safe concurrency without a GIL. Uses std::thread, tokio for async operations.
use std::thread;

fn process_data(data: &str) {
    // Process data
}

fn main() {
    let data = "data";
    let handle = thread::spawn(move || {
        process_data(data);
    });

    handle.join().unwrap();
}

Continuing with advanced examples, each section showcases the unique aspects and best practices of Python and Rust in handling complex programming scenarios.