github

rochacbruno / py2rs

  • четверг, 30 ноября 2017 г. в 03:13:41
https://github.com/rochacbruno/py2rs


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



py2rs

From Python into Rust

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

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

image_2017-11-28_08-03-59

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

Exercises

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

  1. Exercism.io
    Register a new account on exercism.io (using github auth)
    Install exercism command line client on your computer
    Solve some exercises: 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 everything 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. Awesome Rust Newsletter
    https://rust.libhunt.com/
  3. Reddit
    http://reddit.com/r/rust (serious sub-reddit)
    http://reddit.com/r/rustjerk (almost memes only)
  4. 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.

Main Community links

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

Local Communities

Additional learning resources

Facts

  • The language is named Rust because "rust is as close to the bare metal as you can get".,
    in metal theory rust is the chemical layer closest to bare metal.
    (also Wikipedia says that the name was possibly inspired by the name of a Fungi)
  • The Rust trifecta is 1) Memory Safe, 2) Fast 3) Concurrent
  • Rust can be used for web development http://www.arewewebyet.org/
  • Rust can be used for Gaming Development http://arewegameyet.com/
  • Rust can be used for Machine Learning http://www.arewelearningyet.com/
  • Lots of IDEs and Editors supports Rust https://areweideyet.com/
    (VSCode is known to have the better support by now https://marketplace.visualstudio.com/items?itemName=kalitaalexey.vscode-rust)
  • Rust packages are called Crates and are installed by Cargo explore them at http://crates.io
  • In Rust there is no Class but Structs, Enums, Traits, functions and macros!
  • Rust compiler was first writen in OCaml then rewritten in Rust! (Rust is writen Rust!!!)
  • Rust type system is strongly inspired by Haskell
  • Rust functional style is inspired by Erlang
  • Rust type inference is inspired by Python and Ruby
  • The main syntax style is inspired by C and C++
  • There is no automated Garbage Collector so Rust frees memory based on Resource Aquisition RAII (a.k.a Ownership)
  • Rust has Generic Types!!!
  • As Rust is close to bare metal you can ship a program without the inclusion of Rust's runtime which makes easy to distribute programs (no need of dependencies and virtuelenvs management)
  • There are Python code in Rust! Rust build is bootstrapped by Python
  • Graydon Hoare (creator of Rust) is now working at Apple developing the Swift language
  • Rust is the developers most loved language according to Stack Overflow Survey
  • Rust is the most energy efficient language! and that is very important for environment, data center companies and maybe it can help saving your laptop and phone battery in near future.
  • There is an Operating System written in Rust - https://www.redox-os.org/
  • Mozilla released the fastest version of Firefox (quantum) having many parts written on Rust
  • The Rust mascot (unofficial) is called Ferris and it is a crab http://www.rustacean.net/
    (There is no record of the official reason about being a crab, the reasonable history is that it was inspired by the Rusty Crab a common species of crab and also a name of a famous restaurant.)
  • To compliment your fellow Rustaceans don't say cheers!. Say safe! (safe! is also said when toasting with champagne at Rust conferences)

More facts? and curiosities 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 subprocess
multiprocessing * Run external commands 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 Mockers
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 astro-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') Instance initialization (with some default values) derive_new
itertools *stdlib Extra iterators methods itertools
hashlib * Password Hashing libpasta

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 basic 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

Python with typing annotations

It looks more similar to Rust.

def add(a: int, b: int) -> int:
    """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

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

Rust


Communicating between threads

Managing data context between threads.

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

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

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();
}

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

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

json.dump(obj, stdout)

Rust


Object Orientation

Python

playground

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('Garfield')  # Meow Garfield, I'm Grumpy

Rust

playground

struct Cat {
    name: String
}

impl Cat {

    pub fn new<S>(name: S) -> Cat where S: Into<String> {
        Cat { name: name.into() }
    }
    
    pub fn greet<S: Into<String>>(&self, other:S) {
        println!("Meow {}, I'm {}", other.into(), self.name);
    }     
    
}

fn main() {
    let grumpy = Cat::new("Grumpy");
    grumpy.greet("Garfield");  // Meow Garfield, I'm Grumpy
}

NOTE: In Rust, it is best to avoid stringly types APIs so in the above example it would be better if we do let garfield = Cat::new("Garfield") and then make greet to accept an instance of Cat as other argument. If you are interested watch this.


Print Object for Debug/Log

Print formatted object debug information

Python

class Actor:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __repr__(self):
      return str(self.__dict__)

daffy = Actor(
    name='Daffy',
    age=80,
)

print('{!r}'.format(daffy))  # {'name': 'Daffy', 'age': 80}

Rust

#[derive(Debug)]
struct Actor {
    name: String,
    age: i32
}

fn main() {
    let daffy = Actor {name: "Daffy".into(), age: 80};
    println!("{:#?}", daffy);   // Actor {name: "Daffy", age: 80 }
}

Template for new examples

Explanation comes here.

Python

playground

# python code goes here

Rust

playground

// rust code goes here

Credits

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

First published in BrunoRocha.org

With contributions by:

  • Send a PR and include your name and links

toasting-at-cargo-hall