Published in 21:23 of 11/28/2017 by Bruno Rocha
Bruno Rocha There is more to life than increasing its speed!

Published in 21:23 of 11/28/2017

←Home

py2rs - from Python to Rust - Reference Guide

py2rs

From Python into Rust

let x = Rust::from("Python");

A quick reference guide for the Pythonista in process of becoming a Rustacean.

NOTE The original repository for this article is on https://github.com/rochacbruno/py2rs <-- READ THERE FOR UPDATED VERSION

Monty Python - Season 3 - Episode 49

The sketch

Mrs. Jalin: George.
Mr. Jalin: Yes, Gladys.
Mrs. Jalin: There's a man at the door with a moustache.
Mr. Jalin: Tell him I've already got one. (Mrs. Jalin hits him hard with a newspaper) 
          All right, all right. What's he want then?
Mrs. Jalin: He says do we want a documentary on crustaceans.
Mr. Jalin: Crustaceans!
Mrs. Jalin: Yes.
Mr. Jalin: What's he mean, crustaceans?
Mrs. Jalin: CRUSTACEANS!! GASTROPODS! LAMELLIBRANCHS! CEPHALOPODS!
...
Ok...watch it later... let's learn some Rust now...

TOC

Getting Started with Rust

Assuming you already know what is Rust and already decided to start learning it. Here are some steps for you to follow:

  1. Take a tour of Rust Syntax and Coding Style
    https://learnxinyminutes.com/docs/rust/
  2. Watch some screencasts to get basics of Ownership &Borrowing concept
    http://intorust.com/
  3. Follow this set of runnable examples to understand how everything fit together
    https://rustbyexample.com
  4. Now it is time to read your first book, you can pick:

  5. Read some real examples

  6. Patterns and Good Practices

Exercices

Time to put your new knowledge in action solving some exercices.

1) Exercism.io
Register a new account on exercism.io (using github auth)
Install exercism command line client on your computer
Solve some exercices: http://www.exercism.io/languages/rust/about

2) Rust Playground
Run Live Rust Code in the browser with https://play.rust-lang.org/

Getting updated

Now I assume you are addicted to Rust and you want to be updated about averything around it, here are some good links to follow.

1) This Week in Rust Newsletter
https://this-week-in-rust.org/
https://twitter.com/thisweekinrust 2) Reddit
http://reddit.com/r/rust (serious sub-reddit)
http://reddit.com/r/rustjerk (almost memes only)
3) Official Twitter
https://twitter.com/rustlang

Interact with other Rustaceans

Don't be afraid, the Rustaceans are a very receptive species and are cozy with the Pythonistas.

Community links: https://www.rust-lang.org/en-US/community.html

Local

Additional learning resources

Facts

More facts? send a question here or send a Pull Request adding an interest fact to this list.

ferris

Glossary of terms

Term Definition
crate A rust distributable package
ferris The unofficial Crab Mascot
Rustacean The Rust programmer or evangelist or enthusiastic
nightly The unstable toolchain of the Rust compiler
impl Implementation

py2rs

From Python into Rust

let x = Rust::from("Python");

A quick reference guide for the Pythonista in process of becoming a Rustacean.

General

Python Definition Rust
PEP8 Guidelines and conventions RustAPI Guidelines
PEPS Enhancement Proposals / RFC Rust RFCs
PSF Organization / Foundation Mozilla Research
PyCon Main Conference RustConf
Guido Van Rossum Creator Graydon Hoare
1989 First appeared 2010
1991 First Release 2012
PSF License Apache 2.0 and MIT
C Implemented in Rust
.py, .pyw, .pyc File Extensions .rs, .rlib
http://github.com/python/cpython Repository https://github.com/rust-lang/rust
Pyladies, AfroPython Diversity and Inclusion initiative RustBridge
comp.lang.Python Official Users Forum users.rust-lang.org

Environment Tools

Python Definition Rust
requirements.txt Official dependency tracker file Cargo.toml
setup.py Official installator / distributor file Cargo.toml
PyPI Library Repositoty Crates.io
pip Library installation Cargo
setuptools Library distribution Cargo
pbr Library distribution Cargo
pipenv Dependency manager Cargo
twine Package uploader Cargo and Semantic
venv * Isolated environments Cargo
pyinstaller Generate Standalone Executables Cargo
pyenv Install and manage versions of language rustup
sphinx Generate documentation from code rustdoc and Cargo
python Interpreter / Compiler rustc and Cargo
ipython REPL rusti
ipdb Debugger rust-gdb

Libraries and Frameworks

Python Definition Rust
urllib * HTTP calls hyper
requests simplified HTTp calls reqwest
json JSON Parsing loading and dumping serde
pyYAML YAML Parsing loading and dumping serde
lxml XML Parsing loading and dumping RustyXML
csv * CSV parsing rust-csv
datetime * & Dateutils Date & time Chrono
click and argparse CLI Framework clap
docopt CLi Framework docopt
re * Regular Expressions regex
subprocess * Run external commands crossbeam and Rayon
logging * Logging log
Pathlib * Path manipulation fs and fs_extra
cryptography crytography crypto
pickle * Object Serialization RON
heapq * Heap Queue BinaryHeap *
bottle Minimal Web Framework Iron
flask Web Framework Rocket
django Full Stack Web Framrwork Gotham
SQL Alchemy Relational Database ORM Diesel
Pymongo Mongo DB driver mongodb
Jinja 2 Template Engine Tera
pygtk GTk desktop development gtk
pyside QT desktop development rust-qt
pygame 2D UI library / gaming Conrod & Piston
unitest2 Test framework Builtin
nose Test Runner Cargo
pytest Testing Framework and Runner Polish
Flake8 Linter Clippy
autopep8 Auto formatter rustfmt
twisted Network application framework libpnet
AsyncIO * Async application framework Tokio and futures
Pillow Image Manipulation Image
Beautiful Soup HTML Parser html5ever
Hypothesis Data Driven test framework proptest
mock Test Mocking Mockito
bioPython Bioinformathics libraries Rust Bio
Dynaconf Config management Config
itertools * Data Structure Iteration Rust Itertools
Geopython geo Spatial Data Geo Rust
ScikitLearn Machine Learning rusty-machine
mistune Markdown / Common Mark Parser cmark
celery Distributed Computation Antimony
boto AWS clients rusoto
AstroPy Astronomy atro-rust
Numpy Numeric Numeric

Applications

Python Definition Rust
Pelican Static Site generator Cobalt
ansible Infra Orchestration realize
mkdocs Generate documentation and e-books from Markdown mdBook
locust HTTP load test drill
Nameko Microservices Framework fractalide
Quokka CMS CMS NIckel CMS

Useful crates

Add Pythonic features to Rust

Python Definition Rust
{'foo': "bar"} Syntax to create a dict / hashmap maplit
__init__(self, value='default') Initializing instances with default values derive_new
itertools *stdlib Extra iterators methods itertools

Show me The code

From Python to Rust by examples

You can copy-paste and run the Rust examples in https://play.rust-lang.org/ and Python in https://repl.it/languages/python3

Creating a new project

Create a new project with baseic files, entry points, module initializer, dependency and installation artifacts.

Python

$ mkdir {pyproject,pyproject/src}
$ touch {pyproject/src/{__init__.py,__main__.py,program.py},pyproject/{requirements.txt,setup.py}} 
$ echo "-e ." >> pyproject/requirements.txt
$ echo "from setuptools import setup" >> pyproject/setup.py
$ echo "setup(author=..., name=...)" >> pyproject/setup.py

Rust

$ cargo new my-rust-program

Installing new libraries/crates

Python

$ pip install foo

Rust

$ cargo install foo

Running / Compiling

Python

$ python my_python_program.py

Rust

$ cargo run

Hello World

Python

if __name__ == "__main__":
    print("Hello, World")

Rust

fn main() {
  println!("Hello, World");
}

Types and Declarations

Create new objects, values on basic primitive types and also data structures.

Python

age = 80
name = 'daffy'
weight = 62.3
loons = ['bugs', 'daffy', 'taz']
ages = {  # Ages for 2017
    'daffy': 80,
    'bugs': 79,
    'taz': 63,
}

Rust

use std::collections::HashMap;

fn main() {
    let age = 80;
    let name = "daffy";
    let weight = 62.3;
    let mut loons = vec!["bugs", "daffy", "taz"];

    let mut ages = HashMap::new();  // Ages for 2017
    ages.insert("daffy", 80);
    ages.insert("bugs", 79);
    ages.insert("taz", 63);
}

Define a function

Defining a function that takes 2 integer arguments and returns its sum.

Python

def add(a, b):
    "Adds a to b"""
    return a + b

Rust

// Adds a to b
fn add(a: i32, b: i32) -> i32 {
  a + b
}

List/Slice

Creating a list, adding new elements, gettings its length, slicing by index, itarating using for loop and iterating with enumerator.

Python

names = ['bugs', 'taz', 'tweety']
print(names[0])  # bugs
names.append('elmer')
print(len(names))  # 4
print(names[2:])  # ['tweety', 'elmer']

for name in names:
    print(name)

for i, name in enumerate(names):
    print('{} at {}'.format(name, i))

Rust

fn main() {
    let mut names = vec!["bugs", "taz", "tweety"];
    println!("{}", names[0]);  // bugs
    names.push("elmer");
    println!("{}", names.len());  // 4
    println!("{:?}", &names[2..]);  // ["tweety", "elmer"]

    for name in &names {
        println!("{}", name);
    }

    for (i, name) in names.iter().enumerate() {
        println!("{} at {}", i, name);
    }
}

Dict/Map

Create new dictionaries (hash maps), adding new keys and values, changing values, getting by key, checking if a key is containing, etc.

Python


# Creating a new dict and populating it
ages = {}
ages['daffy'] = 80
ages['bugs'] = 79
ages['taz'] = 63

# or doing the same using a for loop
ages = {}
for name, age in [("daffy", 80), ("bugs", 79), ("taz", 63)]:
    ages[name] = age

# or initializing from a list
ages = dict([("daffy", 80), ("bugs", 79), ("taz", 63)])

# or passing key values on creation
ages = {  # Ages for 2017
    'daffy': 80,
    'bugs': 79,
    'taz': 63,
}

ages['elmer'] = 80
print(ages['bugs'])  # 79
print('bugs' in ages)  # True

del ages['taz']

for name in ages:  # Keys
    print(name)

for name, age in ages.items():  # Keys & values
    print('{} is {} years old'.format(name, age))

Rust

use std::iter::FromIterator;
use std::collections::HashMap;

fn main() {

    // Creating a new HashMap and populating it
    let mut ages = HashMap::new();  // Ages for 2017
    ages.insert("daffy", 80);
    ages.insert("bugs", 79);
    ages.insert("taz", 63);

    // or doing the same using a loop
    let mut ages = HashMap::new();
    for &(name, age) in [("daffy", 80), ("bugs", 79), ("taz", 63)].iter() {
        // For non-Copy data, remove & and use iter().clone()
        ages.insert(name, age);
    }

    // or initializing from Array
    let mut ages: HashMap<&str, i32> =  // Ages for 2017
        [("daffy", 80), 
         ("bugs", 79), 
         ("taz", 63)]
        .iter().cloned().collect();

    // or initializing from Vec (Iterator)
    let mut ages: HashMap<&str, i32> =  // Ages for 2017
        HashMap::from_iter(
            vec![
               ("daffy", 80),
               ("bugs", 79),
               ("taz", 63)
            ]
        );

    ages.insert("elmer", 80);
    println!("{}", ages["bugs"]);  // 79
    println!("{}", ages.contains_key("bugs")); // true
    ages.remove("taz");


    for name in ages.keys() {  // Keys
      println!("{}", name);
    }

    for (name, age) in &ages {  // Keys & values
      println!("{} is {} years old", name, age);
    }

}

Pythonic alternative to dict/map in Rust

You can use the maplit crate to load hashmap! macro to have an efficient sugared (a.k.a Pythonic) syntax!

# Cargo.toml
[dependencies]
maplit = "*"

then

#[macro_use] extern crate maplit;

let map = hashmap!{
    "daffy" => 80,
    "bugs" => 79,
    "taz" => 63,
};

set / HashSet

Create a set (a hash of unique keys), add new keys and compute intersection, difference and union

Python


# creating and populating
colors = set()
colors.add("red")
colors.add("green")
colors.add("blue")
colors.add("blue")

# using literal syntax
colors = {'red', 'green', 'blue', 'blue'}

# from an iterator
colors = set(['red', 'green', 'blue', 'blue'])


# deduplication
print(colors)  # {"blue", "green", "red"}

# operations
colors = {'red', 'green', 'blue', 'blue'}
flag_colors = {"red", "black"}

# difference
colors.difference(flag_colors)  # {'blue', 'green'}

# symmetric difference
colors.symmetric_difference(flag_colors)  # {'black', 'blue', 'green'}

# intersection
colors.intersection(flag_colors)  # {'red'}

# unioin
colors.intersection(flag_colors)  # {'black', 'blue', 'green', 'red'}

Rust

use std::collections::HashSet;
use std::iter::FromIterator;

fn main() {

    // creating and populating - type inference
    let mut colors = HashSet::new();
    colors.insert("red");
    colors.insert("green");
    colors.insert("blue");
    colors.insert("blue");

    // from an iterator - explicit type
    let mut colors: HashSet<&str> = HashSet::from_iter(vec!["red", "green", "blue", "blue"]);

    // deduplication
    println!("{:?}", colors); // {"blue", "green", "red"}

    // Operations
    let mut colors: HashSet<&str> = HashSet::from_iter(vec!["red", "green", "blue", "blue"]);
    let mut flag_colors: HashSet<&str> = HashSet::from_iter(vec!["red", "black"]);

    // difference
    colors.difference(&flag_colors); // ["green", "blue"]

    // symmetric difference
    colors.symmetric_difference(&flag_colors); // ["blue", "green", "black"]

    // intersection
    colors.intersection(&flag_colors); // ["red"]

    // union
    colors.union(&flag_colors); // ["red", "blue", "green", "black"]
}

or syntax sugared using maplit crate

#[macro_use] extern crate maplit;

let colors = hashset!{"red", "green", "blue", "blue"};

while and for loops

Looping until a condition is met or over an iterable object.

Python

# While loop

counter = 0
while counter < 10:
    print(counter)
    counter += 1

# infinite while loop
while True:
    print("loop Forever!")

# infinite ehile loop with break
counter = 0
while True:
    print(counter)
    counter += 1
    if counter >= 10:
        break


# while loop with continue
counter = 0
while True:
    counter += 1
    if counter == 5:
        continue
    print(counter)
    if counter >= 10:
        break

# For loop over a list
for color in ["red", "green", "blue"]:
    print(color)

# Enumerating indexes
for  i, color in enumerate(["red", "green", "blue"]):
    print(f"{color} at index {i}")

# For in a range
for number in range(0, 100):
    print(number)  # from 0 to 99

Rust

fn main() {

    // While loop
    let mut counter = 0;
    while counter < 10 {
        println!("{}", counter);
        counter += 1;
    }

    // infinite while loop
    loop {
        println!("Loop forever!");
    }

    // infinite while loop with break
    let mut counter = 0;
    loop {
        println!("{}", counter);
        counter += 1;
        if counter >= 10 { break; }
    }

    // infinite while loop with continue
    let mut counter = 0;
    loop {
        counter += 1;
        if counter == 5 { continue; }
        println!("{}", counter);
        if counter >= 10 { break; }
    }

    // for loop over a list
    for color in ["red", "green", "blue"].iter() {
        println!("{}", color);
    }

    // Enumerating indexes
    for (i, color) in ["red", "green", "blue"].iter().enumerate() {
        println!("{} at index {}", color, i);
    }

    // for in a range
    for number in 0..100 {
        println!("{}", number);  // from 0 to 99
    }
}

Loop Labels

Rust has a looping feature which is not present on Python: Loop labels

'outer: for x in 0..10 {
    'inner: for y in 0..10 {
        if x % 2 == 0 { continue 'outer; } // continues the loop over x
        if y % 2 == 0 { continue 'inner; } // continues the loop over y
        println!("x: {}, y: {}", x, y);
    }
}

Files

Read a text file and iterate its lines printing the content, properly close the file at the end.

Python

from pathlib import Path

with open(Path("/tmp/song.txt")) as fp:
    #  Iterate over lines
    for line in fp:
        print(line.strip())

Rust

use std::io::{BufReader, BufRead};
use std::fs::File;
use std::path::Path;


fn main () {
    let fp = File::open(Path::new("/tmp/song.txt")).unwrap();
    let file = BufReader::new(&fp);
    for line in file.lines() {
        //  Iterate over lines
        println!("{}", line.unwrap());
    }
}

Exceptions/Return Error

Expecting for exceptions and identifying errors.

Python

def div(a, b):
    if b == 0:
        raise ValueError("b can't be 0")
    return a / b

# ...

try:
    div(1, 0)
except ValueError:
    print('OK')

Rust

```

---

### Concurrency

**Python**

```python
thr = Thread(target=add, args=(1, 2), daemon=True)
thr.start()

Rust

```

---

### Communicating between threads

Managing data context between threads.

**Python**

```python
from queue import Queue
queue = Queue()
# ...
# Send message from a thread
queue.put(353)


# ...
# Get message to a thread
val = queue.get()

Rust

```

---

### Sorting

Sorting lists, reversing and using a key.

**Python**

```python
names = ['taz', 'bugs', 'daffy']

# Lexicographical order
names.sort()

# Reversed lexicographical order
names.sort(reverse=True)

# Sort by length
names.sort(key=len)

Rust

```

---

### Web app with Flask / Rocket

**Python**

```python
from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    return 'Hello Python'


if __name__ == '__main__':
    app.run(port=8080)

Rust

#![feature(plugin)]
#![plugin(rocket_codegen)]

extern crate rocket;

#[get("/")]
fn index() -> &'static str {
    "Hello Rust"
}

fn main() {
    rocket::ignite().mount("/", routes![index]).launch();
}

MISSING SOME IMPLEMENTATIONS AND EXAMPLES PLEASE CONTRIBUTE on https://github.com/rochacbruno/py2rs

HTTP Request with error handling

Python

import json
from urlib2 import urlopen

url = 'https://httpbin.org/ip'
try:
    fp = urlopen(url)
except HTTPError as err:
    msg = 'error: cannot get {!r} - {}'.format(url, err)
    raise SystemExit(msg)

try:
    reply = json.load(fp)
except ValueError as err:
    msg = 'error: cannot decode reply - {}'.format(err)
    raise SystemExit(msg)

print(reply['origin'])

Rust

```

---

### Encode and Decode JSON

**Python**

```python
data = '''{
    "name": "bugs",
    "age": 76
}'''
obj = json.loads(data)

json.dump(obj, stdout)

Rust

```


---


### Print Object for Debug/Log 

**Python**

```python
daffy = Actor(
    name='Daffy',
    age=80,
)
print('{!r}'.format(daffy))

Rust

```

---

### Object Orientation

**Python**

```python
class Cat:
    def __init__(self, name):
        self.name = name

    def greet(self, other):
        print("Meow {}, I'm {}".format(other, self.name))

# ...

grumy = Cat('Grumpy')
grumy.greet('Grafield')

Rust

rust


Credits

NOTE The original repository for this article is on https://github.com/rochacbruno/py2rs CONTRIBUTE

Created by Bruno Rocha @rochacbruno inspired by https://www.353.solutions/py2go/index.html

With contributions by:

  • Send a PR and include your name and links
  • Simple Login Extension for Flask in flask · 23:46 of 08/23/2017
  • Publish your Python packages easily using flit in python · 20:19 of 08/22/2017
  • The quality of the python ecosystem in Slides · 21:23 of 06/27/2017

  • comments powered by Disqus Go Top