My Python Learning Journey: Week 4 - Steps I Took, Problems I Faced, and How I Solved Them.

My Python Learning Journey: Week 4 - Steps I Took, Problems I Faced, and How I Solved Them.

Hey everyone, in this week, I learned about the following Python concepts:


  • Inheritance: Single inheritance, Multiple inheritance, and Multilevel inheritance.

  • OOP Methods: super() method and @classmethod.

  • Advanced Concepts: The @property decorator and Operator Overloading in Python.

These are the steps I took to grasp the concepts:


  • Studied the basics of Single, Multiple, and Multilevel inheritance through Python examples.

  • Explored how to call a parent class's method using super() and why it’s useful.

  • Learned the use of @classmethod for defining methods that operate on the class instead of an instance.

  • Practiced with the @property decorator to replace traditional getters and setters.

  • Wrote custom methods to make Python operators (like + , -, and *) work differently with user-defined objects.

These are the problems that I encountered:


  1. Resolving Attribute Conflicts When Using @classmethod Decorator.

  2. Common Inheritance Errors in Python's super() Calling Method.

  3. Understanding the Difference Between __str__ and __add__ Methods in Python.

  4. How to Add Two Objects in Python & Display the Result without __str__ method.

This is how I solved those problems:


1. Resolving Attribute Conflicts When Using @classmethod Decorator.

Problem: I encountered a problem where an instance attribute shadowed a class attribute, causing unexpected behavior i.e, When I set x.a = 10, it created an instance attribute that overrode the class attribute, causing print(x.a) to display the instance value while x.show() still accessed the class attribute.

class Employee:
    a = 5
    @classmethod
    def show(cls):
        print(f"The value of a is: {cls.a}")
x = Employee()
x.a = 10
print(x.a)  # Prints 10 (instance attribute)
x.show()    # Prints 5 (class attribute)

Solution: To resolve this, I ensured the attribute always referred to the class-level value by using the class name to directly refer to the class attribute:

class Employee:
    a = 5
    @classmethod
    def show(cls):
        print(f"The value of a is: {cls.a}")
x = Employee()
x.a = 10
print(Employee.a)  # Prints 5, always uses the class attribute
x.show()           # Prints 5 (class attribute)

2. Common Inheritance Errors in Python's super() Calling Method.

Problem: I encountered a TypeError when using inheritance in Python. In the child class, I called super().__init__() without passing the required arguments to the parent class, which caused this error:

class TwoDvector:  # Parent class
    def __init__(self, i, j):
        self.i = i
        self.j = j

    def show(self):
        print(f"The 2-D vector is: {self.i}i + {self.j}j")

class ThreeDvector(TwoDvector):  # Child class (Inheritance)
    def __init__(self, i, j, k):
        super().__init__()       # Error: Missing arguments for parent class
        self.k = k

    def show(self):
        print(f"The 3-D vector is: {self.i}i + {self.j}j + {self.k}k")

b = ThreeDvector(5, 8, 7)       # This will raise a TypeError
print(b.i, b.j, b.k)
b.show()  
# TypeError: TwoDvector.__init__() missing 2 required positional arguments: 'i' and 'j'

Solution: To fix this, I passed the necessary arguments (i and j) to the parent class using super() method.

class TwoDvector:                # Parent class
    def __init__(self, i, j):
        self.i = i
        self.j = j

    def show(self):
        print(f"The 2-D vector is: {self.i}i + {self.j}j")

class ThreeDvector(TwoDvector):  # Child class (Inheritance)
    def __init__(self, i, j, k):
        super().__init__(i, j)   # Pass i and j to the parent class
        self.k = k

    def show(self):
        print(f"The 3-D vector is: {self.i}i + {self.j}j + {self.k}k")

b = ThreeDvector(5, 8, 7)       # Now works correctly
print(b.i, b.j, b.k)            # Output: 5 8 7
b.show()                        # Output: The 3-D vector is : 5i + 8j + 7k

3. Understanding the Difference Between __str__ and __add__ Methods in Python.

Problem:

  • If we want to print only one object value i.e print(v) like in the below code then only using def __add__(self) gives just a memory address, not the actual values.
class Vector:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    def __add__(self):
        return Vector(self.x + self.y + self.z)
v = Vector(7,8,10)
print(v)    # Output: <__main__.Vector object at 0x000001AA02B96F90>

Solution: To print the value in a readable format, I need to use def __str__(self) method.

class Vector:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    def __add__(self): # Correctly adds two vectors
        return Vector(self.x + self.y + self.z)
    def __str__(self): # Used to return a string representation of the object. 
        return f"{self.x}i + {self.y}j + {self.z}k"

v = Vector(7,8,10)
print(v)    # Output: 7i + 8j + 10k

4. How to Add Two Objects in Python & Display the Result without __str__ method.

Problem:

  • I observed that when trying to add two Vector objects and print the result.

  • I expected that print(v1 + v2) would print the sum of the two vectors, and it worked correctly, but it was printing a string directly. This behavior didn't require the __str__ method.

Solution:

  • The key here is that the __add__ method is returning a string directly, so it doesn’t need __str__ to display the result.

  • Since __add__ returns a string representation, Python automatically prints the result without needing the __str__ method.

class Vector:
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
    def __add__(self, other):  # Correctly add two vectors & return a string
        return f"({self.x + other.x}i + {self.y + other.y}j + {self.z + other.z}k)"

v1 = Vector(7, 8, 10)
v2 = Vector(7, 8, 10)
print(v1 + v2)  # This prints the sum of vectors without __str__ method.
                # Output: (14i + 16j + 20k)

These are the resources that helped me learn: