empa-scientific-it / python-tutorial

Material for a Jupyter-based Python tutorial
MIT License
31 stars 9 forks source link

Errors found in the `object_oriented_programming_advanced` notebook #172

Open yakutovicha opened 10 months ago

despadam commented 10 months ago

Typo in Music Streaming Service exercise: Class User should have attribute username and not name

edoardob90 commented 10 months ago

In the "Banking system" exercise, clarify which kind of interest we want to compute. In the tests we are computing a "simple" interest, while someone might attempt to calculate a "compound" interest. We have to make it clear.

GCatarina commented 10 months ago

In "Store Inventory" exercise, solution with 'pop("type")' method does not pass the tests even though it outputs the correct result.

Code example that works but fails the tests:

computers = [
    {
        "type": "PC",
        "name": "pc_1",
        "price": 1500,
        "quantity": 1,
        "expansion_slots": 2
    },
    {
        "type": "Laptop",
        "name": "laptop_1",
        "price": 1200,
        "quantity": 4,
        "battery_life": 6
    }
]

class Computer:
    def __init__(self,name,price,quantity):
        self.name = name
        self.price = price
        self.quantity = quantity

    def __str__(self):
        return f"Computer with name '{self.name}', price {self.price} CHF and quantity {self.quantity}."

class PC(Computer):
    def __init__(self,name,price,quantity,expansion_slots):
        super().__init__(name,price,quantity)
        self.expansion_slots = expansion_slots

    def __str__(self):
        return super().__str__() + f" This PC has {self.expansion_slots} expansion slots."

class Laptop(Computer):
    def __init__(self,name,price,quantity,battery_life):
        super().__init__(name,price,quantity)
        self.battery_life = battery_life

    def __str__(self):
        return super().__str__() + f" This laptop has a battery life of {self.battery_life} hours."

inventory = []
for computer in computers:
    if computer["type"] == "Computer":
        computer.pop("type")
        inventory.append(Computer(**computer))
    elif computer["type"] == "PC":
        computer.pop("type")
        inventory.append(PC(**computer))
    elif computer["type"] == "Laptop":
        computer.pop("type")
        inventory.append(Laptop(**computer))

sol = []
for it in inventory:
    sol.append(str(it))

print(sol)
yakutovicha commented 10 months ago

In the first exercise, it is not possible to use the define decorator to define Mother and Father classes:

from attrs import define

@define
class Mother:
    eye_color_mother: str

@define
class Father:
    eye_color_father: str

class Child(Mother, Father):
    def __init__(self, eye_color_mother: str, eye_color_father: str):
        Mother.__init__(self, eye_color_mother)
        Father.__init__(self, eye_color_father)
        self.eye_color = self.set_eye_color()

    def set_eye_color(self):
        if self.eye_color_mother == self.eye_color_father:
            return self.eye_color_mother
        return "brown"

An attempt to create a class results in the following error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[2], line 9
      5 @define
      6 class Father:
      7     eye_color_father: str
----> 9 class Child(Mother, Father):
     10     def __init__(self, eye_color_mother: str, eye_color_father: str):
     11         Mother.__init__(self, eye_color_mother)

TypeError: multiple bases have instance lay-out conflict

Replacing the @define decorator with dataclass fixes the issue. But it is still not clear why define is not working.

Some hints from the stackoverflow.