Days 2-8 of my #100DaysOfCode journey: Whew!
John Enad
Posted on April 8, 2023
During days 2-8 of my #100DaysOfCode journey, I faced some challenges. Although I breezed through simpler concepts in the beginning, work picked up as we entered the second quarter of the year. Despite this, I persevered and completed lessons from Day 4 through Day 24 of the Udemy course. Topics covered included randomization, lists, for-loops, range, functions, dictionaries, basic Turtle graphics, and even a Snake game project, which was incredibly fun. I concluded with File, Directories, and Paths at Day 24.
At this point, I decided to delve deeper into Object-Oriented Programming in Python. I found "Python 3: Object-Oriented Programming" by Dusty Phillips on my Packt Publishing account and worked through nearly half of the book before taking a breather.
The author's explanations were excellent. I would highly recommend it.
I was pleasantly surprised by the similarities between Java and Python, despite some syntax differences. The code snippet below demonstrates familiar concepts such as classes, inheritance, constructors, super, getters, setters, try-catch-finally, custom exceptions, throwing (raising) exceptions, overriding, and toString (repr). I found even more similarities as I continued. Here are a few examples:
class InvalidAge(Exception):
pass
class Thing:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self, value):
if not isinstance(value, str):
raise TypeError("Name should be string")
self._name = value
@name.deleter
def name(self):
""" this would be weird though in this particular case """
print("Name deleted")
del self._name
def __repr__(self):
return f"{self.name}"
class Person:
def __init__(self, name):
self.name = name
def say_something(self):
print(f"Hello, my name is {self.name}")
def __repr__(self):
return f"{self.name}"
class Friend(Person):
def __init__(self, name, email, age):
super().__init__(name)
self.email = email
if not isinstance(age, int):
raise TypeError("Age should be integer")
if age < 1 or age >= 120:
raise InvalidAge("Age should be greater than 0 or less than 120")
self.age = age
def say_something(self):
print(f"Hey, What's up?")
def __repr__(self):
return f"{self.name} {self.email} {self.age}"
if __name__ == "__main__":
try:
person = Person("John")
friend = Friend("Jack", "jack@test", 70)
thing = Thing("thing1")
print(person)
print(friend)
print(thing.name)
del thing.name
except TypeError as e:
print("Error: ", e)
finally:
print("finished")
As you can see, a lot of familiar things are demonstrated above like classes, inheritance, constructors, super, getters, setters, try-catch-finally, custom exceptions, throwing (raising) exceptions, overriding and toString (repr). There are even more similarities that I found.
Upon reaching the Data Structures chapter, things became more exciting. I was already familiar with the concept of tuples,
which are immutable objects that store other objects, from my experience with Java and C#. I was pleasantly surprised by tuple unpacking, which is similar to JavaScript's destructuring assignment statement.
name, email, age = ("Matt", "matt@example.com", 25)
print(name, email, age)
Named tuples and data classes were entirely new concepts for me. Named tuples are created using a factory function in the collections package, while data classes are similar to tuples but allow for mutable attributes.
from collections import namedtuple
Superhero = namedtuple("Superhero", ["name", "alias", "level"])
superman = Superhero(name="superman", alias="Clark Kent", level=95)
print(superman)
print(superman.name)
print(superman.alias)
print(superman.level)
Dataclasses on the other hand are almost quite the same as Tuple in that it allows named fields however, one huge difference is that Dataclasses are not immutable. It's attributes can be updated and one could even add more attributes to them.
from dataclasses import make_dataclass
Superhero = make_dataclass("Superhero", ["name", "alias", "level"])
superman = Superhero(name="superman", alias="Clark Kent", level=95)
print(superman)
print(superman.name)
print(superman.alias)
print(superman.level)
A more common way to define dataclasses is to use a class decorate called @dataclass
from dataclasses import dataclass
@dataclass
class Superhero:
name: str
alias: str
level: int
superman = Superhero(name="superman", alias="Clark Kent", level=95)
print(superman)
print(superman.name)
print(superman.alias)
print(superman.level)
Dictionaries seemed pretty standard at first glance. However, defaultdict and Counter methods really caught my attention due to their elegance and compactness.
superheroes = {
"superman": ("Clark Kent", 95),
"batman": ("Bruce Wayne", 40)
}
print(superheroes["superman"])
print(superheroes["batman"])
As expected, we get a KeyError when we try to access a key that doesn’t exist in the dictionary.
print(superheroes["flash"])
And one way around it is the use the get method on the dictionary:
print(superheroes.get("flash", "Not a superhero"))
Now, these next two methods really caught me by surprise and ones that I really like: defaultdict and Counter.
from collections import defaultdict
def num_frequency(num_list):
totals = defaultdict(int)
for value in num_list:
totals[value] += 1
return totals
numbers = [5, 3, 2, 5, 2]
print(num_frequency(numbers))
The code above figures out the frequency of numbers and puts them in a dictionary. But, if you think it's not possible to make
the code even more compact, you're in for a big surprise. I certainly was:
from collections import Counter
numbers = [5, 3, 2, 5, 2]
print(Counter(numbers))
Guess what, it does the same thing but with even less code!
And another equally impressive example:
from collections import Counter
responses = ["superman", "batman", "superman", "superman", "flash", "batman", "superman"]
print(f"The children voted for {Counter(responses).most_common(1)[0][0]}")
print(f"The number of votes for this superhero were: {Counter(responses).most_common(1)[0][1]}")
It's only been eight days, and I feel like I'm making excellent progress. I hope to maintain this pace for the remaining 92 days.
Until next time!
Posted on April 8, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.