rochacbruno / py2rs
- четверг, 30 ноября 2017 г. в 03:13:41
A quick reference guide for the Pythonista in the process of becoming a Rustacean
let x = Rust::from("Python");
A quick reference guide for the Pythonista in process of becoming a Rustacean.
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...
Assuming you already know what is Rust and already decided to start learning it. Here are some steps for you to follow:
Rust Essentials
A good introduction to Rust language in a more
superficial
approach which results in a very pleasant and easy reading, recommended even for those who are not experienced with low level systems languages.
TRPL (The Rust Programming language Book)
A complete Guide to Rust Language
https://doc.rust-lang.org/book/
Time to put your new knowledge in action solving some exercises.
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
Rust Playground
Run Live Rust Code in the browser with https://play.rust-lang.org/
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.
Don't be afraid, the Rustaceans are a very receptive species and are cozy with the Pythonistas.
https://www.rust-lang.org/en-US/community.html
Brazil
Indonesia
Add your country/city here, send a Pull Request.
'lifetimes
and &
) https://jvns.ca/blog/2017/11/27/rust-ref/trifecta
is 1) Memory Safe, 2) Fast 3) ConcurrentCrates
and are installed by Cargo
explore them at http://crates.ioMore facts? and curiosities send a question here or send a Pull Request adding an interest fact to this list.
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 |
let x = Rust::from("Python");
A quick reference guide for the Pythonista in process of becoming a Rustacean.
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 |
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 |
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 |
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 |
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 |
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
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
Python
$ pip install foo
Rust
$ cargo install foo
Python
$ python my_python_program.py
Rust
$ cargo run
Python
if __name__ == "__main__":
print("Hello, World")
Rust
fn main() {
println!("Hello, World");
}
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);
}
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
}
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);
}
}
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);
}
}
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,
};
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"};
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
}
}
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);
}
}
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());
}
}
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
Python
thr = Thread(target=add, args=(1, 2), daemon=True)
thr.start()
Rust
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 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
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();
}
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
Python
data = '''{
"name": "bugs",
"age": 76
}'''
obj = json.loads(data)
json.dump(obj, stdout)
Rust
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('Garfield') # Meow Garfield, I'm Grumpy
Rust
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 dolet garfield = Cat::new("Garfield")
and then makegreet
to accept an instance ofCat
asother
argument. If you are interested watch this.
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 }
}
Explanation comes here.
Python
# python code goes here
Rust
// rust code goes here
Created by Bruno Rocha @rochacbruno inspired by https://www.353.solutions/py2go/index.html
First published in BrunoRocha.org
With contributions by: