DEV Community

Hroney
Hroney

Posted on

All Things Python (in-so-far as I've been using it!)

Hello!

Here marks another phase completed with #flatironschool! I feel as though this phase (phase 3) was quite a different approach to the learning process.

First off - this phase was done in a new language, Python!

Now... At first (And possibly even still...) It's not my favorite of the languages I've been introduced to. That being said - I adore object oriented programming and I thought I'd share some of what I've learned.

But, before we dive into Object-oriented programming - let's mark out something I have enjoyed about Python.

It's clear and concise in its language! If I wanted to consume every cookie in the cookie jar, it's as easy as looping through it like so:

for cookie in cookie_jar:
    consume(cookie)
Enter fullscreen mode Exit fullscreen mode

That same could be done in javascript but would look something like...

cookie_jar.forEach((cookie) => {consume(cookie)};
// or
for (let cookie of cookie_jar) { consume(cookie);
Enter fullscreen mode Exit fullscreen mode

The javascript is far less readable out the box.

This is just one example.

Printing to the console is straightforward in both. But Python just reads more easily.

print("foo")
Enter fullscreen mode Exit fullscreen mode
console.log("foo"
Enter fullscreen mode Exit fullscreen mode

Checking the length of an array or string makes more sense to be a wrapper around the object rather than a function OF the object.

len(["1","2","3"])
Enter fullscreen mode Exit fullscreen mode
["1","2","3"].length()
Enter fullscreen mode Exit fullscreen mode

But I enjoy most of all - classes.

Let's look at an example of a class and break it down line by line.

Person.py

1. # lib/person/Person.py
2. from lib.person._Person import PersonMethods
3. 
4. class Person(PersonMethods):
5. 
6.     def __init__(self,name):
7.         self.name = name
8. 
9.     @property
10.     def name(self):
11.         return self._name
12. 
13.     @name.setter
14.     def name(self, name):
15.         if isinstance(name, str) and len(name):
16.             self._name = name
17.         else:
18.             raise ValueError(
19.                 "Name must be a non-empty string"
20.             )
Enter fullscreen mode Exit fullscreen mode
Breakdown

Line 1: A Single line comment indicating the file path.

Line 2: from lib.person._Person import PersonMethods Imports the PersonMethods class from the _Player module.

Line 4: class Person(PersonMethods): Defines a new class named Person that inherits from the PersonMethods class imported on Line 2. Inheritance allows a class to inherit attributes and methods from another class. In this case, separating methods from Getters / Setters.

Line 6: __init__ is a Constructor. This is a special method that is called when a new instance of the class is instantiated. There are two parameters to the constructor here, self and name. self refers to the instance of the class and is not expressly passed into the constructor upon creation. name is a string (in this case) that is passed into the constructor when initializing the instance.

Line 7: self.name = name This line assigns the value of name that was passed in on line 6 into an attribute of the current instance self.

Line 9 - 11: @property is a decorator used to define a property. Properties provide a way to customize attribute access. For example:

person = Person("John")
print(person.name) # This will print "John"
Enter fullscreen mode Exit fullscreen mode

However this is equivalent to calling the name() method on the instance.

print(person.name()) # This will also print "John"
Enter fullscreen mode Exit fullscreen mode

By using the @property decorator, it allows us to more cleanly access the attribute as though it were a direct attribute.

Line 13: @name.setter is a decorator that defines a setter method for the name property.

Line 14: def name(self, name): defines the name method as a setter based on the decorator in line 13.

Line 15: if isinstance(name, str) and len(name): This is our first bit of logic! This line checks if the value passed into the setter, name, is a non-empty string. isinstance() is a function to check if the value is an instance of the string class and the len() function checks if the string has a length greater than 0

Line 17 - 20: else: raise ValueError("Name....") this line only fires if the value passed into the setter method is not a valid string. It will raise a ValueError with the message attached.

All in all, by defining a setter method for the name property, the name attribute of an instance Person can be modified using assignment syntax. For example:

person = Person("John")
person.name = "Alice" # Changes the name of person
Enter fullscreen mode Exit fullscreen mode

_Person.py

1. # lib/person/_Person.py
2. 
3. class PersonMethods:
4. 
5.     def say_name(self):
6.         return f"My name is {self.name}
Enter fullscreen mode Exit fullscreen mode

Breakdown

Line 1: A Single line comment indicating the file path.

Line 3: class PersonMethods: defines a new class PersonMethods that, unlike Person, does not inherit any methods. Instead, this class has a single method say_name().

Line 5: def say_name(self): definds a method named say_name within the method that has the self parameter, indicating that this is an instance method (a method specifically used by each instance of the class rather than the class itself).

Line 6: return f"My name is {self.name}" returns a string formatted using string interpolation.

All together now!

So! By inheriting from PersonMethods, instances of the Person class gain access to the methods defined in the PersonMethods class! For example, the say_name() method we created earlier can be invoked directly on instances of the Person class!

person = Person("John")
print(person.say_name()) # Output: "My name is John"
Enter fullscreen mode Exit fullscreen mode

This illustrates how the Person class in Person.py benefits from the methods encapsulated in the PersonMethods class defined in _Person.py!

A Caveat to Python...

While I love the object oriented programming paradigm... Python has a major annoyance for my organized brain...

The indentation! 4 spaces!? With Javascript, just wrap everything in curly braces {}. Boom! You know where your scope lines are.

This whitespace sensitivity to define block structure is a real visual problem for me. I appreciate the explicit block delimiters that javascript has with {}.

I learned a lot more about Python but this is just a neat little explanation of something I found fun to learn.

Top comments (0)