Protocols vs. Traits
-Python has a concept called protocols, sometimes referred to as special methods, or "dunder methods" implemented on +
Python has a concept called protocols, sometimes referred to as special methods, or "dunder methods" implemented on
built-in types in the standard library.
For example, the __str__
method is used to implement the str()
function, which returns the string representation of an object.
Th __repr__
method is used to implement the repr()
function, which returns a string containing a printable representation of an object.
Python: Pro
if age > 0 and isinstance(age, int):
self.age = age
else:
- raise ValueError("Age must be a positive integer")
+ raise ValueError("Age must be a positive integer")
def __str__(self) -> str:
- return f"{self.name} is {self.age} years old"
+ return f"{self.name} is {self.age} years old"
def __repr__(self) -> str:
- return f"Person: {self.name}, {self.age}"
+ return f"Person: {self.name}, {self.age}"
One limitation of Python's type system that's worth noting is that it treats all integers as int
types, even if they
are unsigned. In this case, the age of a person should be a positive integer, so we need to check for this by using
@@ -209,13 +209,13 @@
Python: Pro
more powerful, while also being stricter than Python's.
We can now create a Person
object via a function and print it to the console by running the code via main.py
.
def run1() -> None:
- person = Person("Megan", 28)
+ person = Person("Megan", 28)
print(person)
print(repr(person))
- """
+ """
Megan is 28 years old
Person: Megan, 28
- """
+ """
When we print the person
object, the __str__
method is called, and when we print the repr
object,
the __repr__
method is called, thus producing slightly different outputs depending on what we want to display.
@@ -252,13 +252,13 @@
Rust: Traits
an object's behavior.
impl fmt::Display for Person {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{} is {} years old", self.name, self.age)
+ write!(f, "{} is {} years old", self.name, self.age)
}
}
impl fmt::Debug for Person {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Person: {}, {}", self.name, self.age)
+ write!(f, "Person: {}, {}", self.name, self.age)
}
}
@@ -266,9 +266,9 @@ Rust: Traits
strict type system needs to know upfront what the user wants to do with the object's types prior to displaying them.
With these bits in place, we can now create a Person
object via a function and print it to the console by running the code via main.rs
.
fn run1() {
- let p = Person::new("Megan", 28);
- println!("{}", p);
- println!("{:?}", p);
+ let p = Person::new("Megan", 28);
+ println!("{}", p);
+ println!("{:?}", p);
/*
Megan is 28 years old
Person: Megan, 28
diff --git a/pieces/intro/sets_vs_hashsets.html b/pieces/intro/sets_vs_hashsets.html
index a32d755..db1680a 100644
--- a/pieces/intro/sets_vs_hashsets.html
+++ b/pieces/intro/sets_vs_hashsets.html
@@ -187,24 +187,24 @@ Python
Consider the following function in which we define a set of processors.
def run9() -> None:
processors = {
- "Intel Core i9",
- "Intel Core i7",
- "Intel Core i5",
- "AMD Ryzen 7",
- "AMD Ryzen 5",
- "AMD Ryzen 3",
+ "Intel Core i9",
+ "Intel Core i7",
+ "Intel Core i5",
+ "AMD Ryzen 7",
+ "AMD Ryzen 5",
+ "AMD Ryzen 3",
}
# Duplicate values are ignored
- processors.add("Intel Core i7")
- processors.add("AMD Ryzen 5")
+ processors.add("Intel Core i7")
+ processors.add("AMD Ryzen 5")
# Check for presence of value
- is_item_in_set = "AMD Ryzen 3" in processors
- print(f'Is "AMD Ryzen 3" in the set of processors?: {is_item_in_set}')
+ is_item_in_set = "AMD Ryzen 3" in processors
+ print(f'Is "AMD Ryzen 3" in the set of processors?: {is_item_in_set}')
The purpose of the above function is to check for the presence of a value in the set of processors.
When we add duplicate values to the set, they are ignored.
Running the above function via main.py
gives us the following output:
-Is "AMD Ryzen 3" in the set of processors?: True
+Is "AMD Ryzen 3" in the set of processors?: True
Rust
We define the below function in Rust, where we define a hashset of processors.
@@ -212,19 +212,19 @@ Rust
fn run9() {
let mut processors = HashSet::new();
- processors.insert("Intel Core i9");
- processors.insert("Intel Core i7");
- processors.insert("Intel Core i5");
- processors.insert("AMD Ryzen 7");
- processors.insert("AMD Ryzen 5");
- processors.insert("AMD Ryzen 3");
+ processors.insert("Intel Core i9");
+ processors.insert("Intel Core i7");
+ processors.insert("Intel Core i5");
+ processors.insert("AMD Ryzen 7");
+ processors.insert("AMD Ryzen 5");
+ processors.insert("AMD Ryzen 3");
// Duplicate values are ignored
- processors.insert("Intel Core i7");
- processors.insert("AMD Ryzen 5");
+ processors.insert("Intel Core i7");
+ processors.insert("AMD Ryzen 5");
// Check for presence of value
- let value = "AMD Ryzen 3";
+ let value = "AMD Ryzen 3";
println!(
- "Is \"AMD Ryzen 3\" in the hashset of processors?: {}",
+ "Is \"AMD Ryzen 3\" in the hashset of processors?: {}",
processors.contains(&value)
);
}
@@ -232,21 +232,21 @@ Rust
The purpose of the above function is to check for the presence of a value in the hashset of
processors. When we add duplicate values to the hashset, they are ignored.
Running the function via main.rs
gives us the same output as in Python:
-Is "AMD Ryzen 3" in the hashset of processors?: true
+Is "AMD Ryzen 3" in the hashset of processors?: true
Takeaways
Python and Rust contain collections that allow for the storage of unique items. A key difference is
that Python's set
can contain items of any type, while Rust's HashSet
can only contain items of
the same type that were specified at the time of initialization.
In Python, the following set
containing multiple types is valid, as they are all hashable.
-example = {1, "hello", 3.14}
+example = {1, "hello", 3.14}
In Rust, the compiler enforces that all items in the set are of the same type specified at the time
of initialization, or by inferring the first value's type.
let example = HashSet::new();
example.insert(1);
// This errors because the first value specified the key as u32 or similar
-example.insert("hello");
+example.insert("hello");
// This is valid
example.insert(3);
diff --git a/pieces/intro/single_line_if_else.html b/pieces/intro/single_line_if_else.html
index 7287c8c..3cd72f8 100644
--- a/pieces/intro/single_line_if_else.html
+++ b/pieces/intro/single_line_if_else.html
@@ -197,12 +197,12 @@ Python
int
types, even if they
are unsigned. In this case, the age of a person should be a positive integer, so we need to check for this by using
@@ -209,13 +209,13 @@ We can now create a Person
object via a function and print it to the console by running the code via main.py
.
def run1() -> None:
- person = Person("Megan", 28)
+ person = Person("Megan", 28)
print(person)
print(repr(person))
- """
+ """
Megan is 28 years old
Person: Megan, 28
- """
+ """
When we print the person
object, the __str__
method is called, and when we print the repr
object,
the __repr__
method is called, thus producing slightly different outputs depending on what we want to display.
@@ -252,13 +252,13 @@
Rust: Traits
an object's behavior.impl fmt::Display for Person {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{} is {} years old", self.name, self.age)
+ write!(f, "{} is {} years old", self.name, self.age)
}
}
impl fmt::Debug for Person {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "Person: {}, {}", self.name, self.age)
+ write!(f, "Person: {}, {}", self.name, self.age)
}
}
@@ -266,9 +266,9 @@ Rust: Traits
strict type system needs to know upfront what the user wants to do with the object's types prior to displaying them.With these bits in place, we can now create a Person
object via a function and print it to the console by running the code via main.rs
.
fn run1() {
- let p = Person::new("Megan", 28);
- println!("{}", p);
- println!("{:?}", p);
+ let p = Person::new("Megan", 28);
+ println!("{}", p);
+ println!("{:?}", p);
/*
Megan is 28 years old
Person: Megan, 28
diff --git a/pieces/intro/sets_vs_hashsets.html b/pieces/intro/sets_vs_hashsets.html
index a32d755..db1680a 100644
--- a/pieces/intro/sets_vs_hashsets.html
+++ b/pieces/intro/sets_vs_hashsets.html
@@ -187,24 +187,24 @@ Python
Consider the following function in which we define a set of processors.
def run9() -> None:
processors = {
- "Intel Core i9",
- "Intel Core i7",
- "Intel Core i5",
- "AMD Ryzen 7",
- "AMD Ryzen 5",
- "AMD Ryzen 3",
+ "Intel Core i9",
+ "Intel Core i7",
+ "Intel Core i5",
+ "AMD Ryzen 7",
+ "AMD Ryzen 5",
+ "AMD Ryzen 3",
}
# Duplicate values are ignored
- processors.add("Intel Core i7")
- processors.add("AMD Ryzen 5")
+ processors.add("Intel Core i7")
+ processors.add("AMD Ryzen 5")
# Check for presence of value
- is_item_in_set = "AMD Ryzen 3" in processors
- print(f'Is "AMD Ryzen 3" in the set of processors?: {is_item_in_set}')
+ is_item_in_set = "AMD Ryzen 3" in processors
+ print(f'Is "AMD Ryzen 3" in the set of processors?: {is_item_in_set}')
The purpose of the above function is to check for the presence of a value in the set of processors.
When we add duplicate values to the set, they are ignored.
Running the above function via main.py
gives us the following output:
-Is "AMD Ryzen 3" in the set of processors?: True
+Is "AMD Ryzen 3" in the set of processors?: True
Rust
We define the below function in Rust, where we define a hashset of processors.
@@ -212,19 +212,19 @@ Rust
fn run9() {
let mut processors = HashSet::new();
- processors.insert("Intel Core i9");
- processors.insert("Intel Core i7");
- processors.insert("Intel Core i5");
- processors.insert("AMD Ryzen 7");
- processors.insert("AMD Ryzen 5");
- processors.insert("AMD Ryzen 3");
+ processors.insert("Intel Core i9");
+ processors.insert("Intel Core i7");
+ processors.insert("Intel Core i5");
+ processors.insert("AMD Ryzen 7");
+ processors.insert("AMD Ryzen 5");
+ processors.insert("AMD Ryzen 3");
// Duplicate values are ignored
- processors.insert("Intel Core i7");
- processors.insert("AMD Ryzen 5");
+ processors.insert("Intel Core i7");
+ processors.insert("AMD Ryzen 5");
// Check for presence of value
- let value = "AMD Ryzen 3";
+ let value = "AMD Ryzen 3";
println!(
- "Is \"AMD Ryzen 3\" in the hashset of processors?: {}",
+ "Is \"AMD Ryzen 3\" in the hashset of processors?: {}",
processors.contains(&value)
);
}
@@ -232,21 +232,21 @@ Rust
The purpose of the above function is to check for the presence of a value in the hashset of
processors. When we add duplicate values to the hashset, they are ignored.
Running the function via main.rs
gives us the same output as in Python:
-Is "AMD Ryzen 3" in the hashset of processors?: true
+Is "AMD Ryzen 3" in the hashset of processors?: true
Takeaways
Python and Rust contain collections that allow for the storage of unique items. A key difference is
that Python's set
can contain items of any type, while Rust's HashSet
can only contain items of
the same type that were specified at the time of initialization.
In Python, the following set
containing multiple types is valid, as they are all hashable.
-example = {1, "hello", 3.14}
+example = {1, "hello", 3.14}
In Rust, the compiler enforces that all items in the set are of the same type specified at the time
of initialization, or by inferring the first value's type.
let example = HashSet::new();
example.insert(1);
// This errors because the first value specified the key as u32 or similar
-example.insert("hello");
+example.insert("hello");
// This is valid
example.insert(3);
diff --git a/pieces/intro/single_line_if_else.html b/pieces/intro/single_line_if_else.html
index 7287c8c..3cd72f8 100644
--- a/pieces/intro/single_line_if_else.html
+++ b/pieces/intro/single_line_if_else.html
@@ -197,12 +197,12 @@ Python