Update page 'Day 3 Homework - Karen'

2023-04-03 17:20:36 +02:00
parent 95b4c89537
commit 0ca4ab7b76
+140 -3
@@ -41,7 +41,7 @@ class BoundedInt():
self.min = min self.min = min
self.max = max self.max = max
``` ```
It's the first draft I have made to meet the requirement; however, the result returns to be "❌ Test 2 failed!", so I want to check i to see what happends to this result and the modified `BoundedInt` is shown as: It's the first draft I have made to meet the requirement; however, the result returns to be "❌ Test 1 failed!", so I want to check i to see what happends to this result and the modified `BoundedInt` is shown as:
``` ```
class BoundedInt(): class BoundedInt():
@@ -74,18 +74,155 @@ The result after runnning this modified script says "Initial value 3735928559 is
**3. Read this, and the paragraph below it: https://docs.python.org/3/reference/datamodel.html?highlight=__int__#object.__add__** **3. Read this, and the paragraph below it: https://docs.python.org/3/reference/datamodel.html?highlight=__int__#object.__add__**
**4. What do you think the types of x and y are? Guess, without checking first. What are they, actually? You can use the debugger's local window to find out.** **4. What do you think the types of x and y are? Guess, without checking first. What are they, actually? You can use the debugger's local window to find out.**
Before checking, I guess x and y are integers because they are used as objects in arithmetic operations. However, I check their types in debugger's local window with the following sample and I find that they can be objects of any type, as long as they implement the `__add__()` method.
```
class Data:
def __init__(self, value):
self.value = value
def __add__(self, other):
return Data(self.value + other.value)
a = Data('a')
b = Data('b')
c = a + b
print(c.value)
```
**5. Don't forget that you can access the value of a BoundedInt by using either `.i` on it, or `int()`, now that you've passed test 1.** **5. Don't forget that you can access the value of a BoundedInt by using either `.i` on it, or `int()`, now that you've passed test 1.**
**6. Modify the template to pass test 2, which checks that:** **6. Modify the template to pass test 2, which checks that:**
* Your class implements the + operator. * Your class implements the + operator.
* It throws ValueError when attempting to add another BoundedInt that would exceed `self.max`. * It throws ValueError when attempting to add another BoundedInt that would exceed `self.max`.
To implement the addition operation, an `__add__()` method should be included here in the template.
```
class BoundedInt():
def __init__(self, i, min, max):
"""
Create a bounded integer.
Args:
i (int): The initial value of the integer.
min (int): The minimum value of the integer.
max (int): The maximum value of the integer.
"""
self.i = min if i < min else (max if i > max else i)
self.min = min
self.max = max
def __int__(self):
return self.i
def __add__(self, other):
result = self.i + other.i
if result > self.max:
raise ValueError("Result exceeds maximum value")
return BoundedInt(result, self.min, self.max)
```
**7. Do the same as 6, but for subtraction, to pass test 3.** **7. Do the same as 6, but for subtraction, to pass test 3.**
Similarly, we just use the subtraction operator `__sub__()` in the `BoundedInt` class.
```
class BoundedInt():
def __init__(self, i, min, max):
self.i = min if i < min else (max if i > max else i)
self.min = min
self.max = max
def __int__(self):
return self.i
def __sub__(self, other):
res = self.i - other.i
if res < self.min:
raise ValueError(f"Result {res} is less than the minimum value {self.min}")
return BoundedInt(res, self.min, self.max)
```
Furthermore, to pass test 3, the range of `bi5` needs to be change as the initial value 2 is outside the range [0, 1]. For instance, if we change the range to be [0, 4], test 3 will pass.
```
class BoundedIntTester:
def __init__(self):
pass
def test3(self):
"""
Test that addition works for two BoundedInts, and throws an error if the bounds are exceeded.
"""
bi4 = BoundedInt(1, min = 0, max = 1)
bi5 = BoundedInt(2, min = 0, max = 4)
try:
bi6 = bi4 - bi5 # 1 - 2 = (-1), which is less than min = 0
print(f"❌ Test 3 failed!")
except ValueError as err:
print(f"✅ Test 3 passed!")
tester = BoundedIntTester()
tester.test3()
```
**8. Modify the template so it also supports adding a regular integer to a BoundedInt, to pass test 4. Note that you can use `isinstance()` to determine the class of a variable.** **8. Modify the template so it also supports adding a regular integer to a BoundedInt, to pass test 4. Note that you can use `isinstance()` to determine the class of a variable.**
```
class BoundedInt():
def __init__(self, i, min, max):
if i < min or i > max:
raise ValueError(f"Initial value {i} is outside the range [{min}, {max}]")
self.i = i
self.min = min
self.max = max
def __add__(self, other):
if isinstance(other, BoundedInt):
result = self.i + other.i
if result < self.min or result > self.max:
raise ValueError(f"Result {result} is out of bounds [{self.min}, {self.max}]")
return BoundedInt(result, self.min, self.max)
else:
return BoundedInt(self.i + other, self.min, self.max)
```
**9. Same as 8, but for subtraction.** **9. Same as 8, but for subtraction.**
```
class BoundedInt():
def __init__(self, i, min, max):
if i < min or i > max:
raise ValueError(f"Initial value {i} is outside the range [{min}, {max}]")
self.i = i
self.min = min
self.max = max
def __sub__(self, other):
if isinstance(other, int):
if self.i - other < self.min:
raise ValueError("ValueError: The result exceeds the minimum limit.")
return BoundedInt(self.i - other, self.min, self.max)
elif isinstance(other, BoundedInt):
if self.i - other.i < self.min:
raise ValueError("ValueError: The result exceeds the minimum limit.")
return BoundedInt(self.i - other.i, self.min, self.max)
```
**10. You don't have to implement the code, but think about how you would change the template so it could allow adding a BoundedInt to an emoji, if there was a hypothetical function sentiment(emoji) which returned a floating point number from -10.0 to 10.0 which indicated whether the emoji was happy or sad. e.g. BoundedInt(1, min = 1, max = 10) + 😁 would raise `ValueError`.** **10. You don't have to implement the code, but think about how you would change the template so it could allow adding a BoundedInt to an emoji, if there was a hypothetical function sentiment(emoji) which returned a floating point number from -10.0 to 10.0 which indicated whether the emoji was happy or sad. e.g. BoundedInt(1, min = 1, max = 10) + 😁 would raise `ValueError`.**
​ I think initially we need to check if the other operand is an emoji and if it is, to call the hypothetical function and raise an error if the result is out of bounds. Here, I just draft a script to try to do this task with comments for each step. I didn't try to run it but hope it works.
```
def __add__(self, other):
if isinstance(other, BoundedInt):
# If the other operand is a BoundedInt, call the existing __add__ method
return BoundedInt(self.i + other.i, min=self.min, max=self.max)
elif hasattr(other, 'sentiment') and callable(other.sentiment):
# hasattr() method returns true if an object has the given named attribute and false if it does not
# I am not sure whether I use it correctly here or I should use hasattr(x, "__call__")
# If the other operand has a sentiment function, call it
sentiment_val = other.sentiment()
if self.min <= self.i + sentiment_val <= self.max:
# If the result is within bounds, create a new BoundedInt
return BoundedInt(self.i + sentiment_val, min=self.min, max=self.max)
else:
# Otherwise, raise a ValueError
raise ValueError("Resulting value is outside of bounds.")
else:
# If the other operand is neither a BoundedInt nor has a sentiment function, raise a TypeError
raise TypeError("Unsupported operand type for +: 'BoundedInt' and '{}'".format(type(other)))
```