mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
fix(curriculum): update Python V9 setter examples to call setter in __init__ (#66233)
Co-authored-by: majestic-owl448 <26656284+majestic-owl448@users.noreply.github.com>
This commit is contained in:
@@ -2279,7 +2279,7 @@ print(account.__balance) # AttributeError: 'Wallet' object has no attribute '__b
|
||||
```py
|
||||
class Circle:
|
||||
def __init__(self, radius):
|
||||
self._radius = radius
|
||||
self.radius = radius # Calling the setter
|
||||
|
||||
@property
|
||||
def radius(self): # A getter to get the radius
|
||||
@@ -2295,12 +2295,14 @@ print(my_circle.radius) # 3
|
||||
print(my_circle.area) # 28.26
|
||||
```
|
||||
|
||||
Using self.radius inside `__init__()` ensures the setter runs during object creation, so invalid radius values are caught immediately.
|
||||
|
||||
- **Creating a Setter**: To create the setter that will set the radius, you have to define another method with the same name and use `@<property_name>.setter` above it:
|
||||
|
||||
```py
|
||||
class Circle:
|
||||
def __init__(self, radius):
|
||||
self._radius = radius
|
||||
self.radius = radius # Calling the setter
|
||||
|
||||
@property
|
||||
def radius(self): # A getter to get the radius
|
||||
@@ -2326,7 +2328,7 @@ my_circle.radius # This will call the getter
|
||||
my_circle.radius = 4 # This will call the setter
|
||||
```
|
||||
|
||||
When setting a value, you should not assign to the property name itself because that will cause a `RecursionError`. Use a separate internal name, often with an underscore, to store the value.
|
||||
Inside the setter, you should not assign to the property name itself because that will cause a `RecursionError`.
|
||||
|
||||
- **Deleter**: After setting and getting a value with setter and getter, you can control how it is deleted with a `deleter`. A deleter runs custom logic when you use the `del` statement on a property. To create a deleter, you use the `@<property_name>.deleter` decorator.
|
||||
|
||||
|
||||
+7
-5
@@ -12,7 +12,7 @@ A setter is a method used to set the value of an attribute, allowing for validat
|
||||
```py
|
||||
class Person:
|
||||
def __init__(self, name):
|
||||
self._name = name
|
||||
self.name = name # Calling the setter
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@@ -76,14 +76,16 @@ class Employee:
|
||||
|
||||
def __repr__(self):
|
||||
return f"Employee('{self.name}', '{self.level}')"
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
|
||||
--fcc-editable-region--
|
||||
@property
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
|
||||
+10
-8
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68c809c990f253912a9e9209
|
||||
title: Step 21
|
||||
title: Step 22
|
||||
challengeType: 20
|
||||
dashedName: step-21
|
||||
dashedName: step-22
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -60,11 +60,11 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if not isinstance(level, str):
|
||||
raise TypeError("'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self.name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
@@ -77,12 +77,14 @@ class Employee:
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
--fcc-editable-region--
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
|
||||
self._name = new_name
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
+8
-6
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68c80b63ca4e5eadf1fac738
|
||||
title: Step 22
|
||||
title: Step 23
|
||||
challengeType: 20
|
||||
dashedName: step-22
|
||||
dashedName: step-23
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -45,11 +45,11 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if not isinstance(level, str):
|
||||
raise TypeError("'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self.name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
@@ -62,14 +62,16 @@ class Employee:
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
--fcc-editable-region--
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
if not isinstance(new_name, str):
|
||||
raise TypeError("'name' must be a string.")
|
||||
self._name = new_name
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
+5
-5
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68c9a09163d4a42e9bc9b638
|
||||
title: Step 23
|
||||
title: Step 24
|
||||
challengeType: 20
|
||||
dashedName: step-23
|
||||
dashedName: step-24
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -36,11 +36,11 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if not isinstance(level, str):
|
||||
raise TypeError("'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self.name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
|
||||
+5
-5
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68c9a624fd54288f694ebdbf
|
||||
title: Step 24
|
||||
title: Step 25
|
||||
challengeType: 20
|
||||
dashedName: step-24
|
||||
dashedName: step-25
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -33,11 +33,11 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if not isinstance(level, str):
|
||||
raise TypeError("'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self.name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
|
||||
+8
-6
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68c9a72c9dab42a15ce6972b
|
||||
title: Step 25
|
||||
title: Step 26
|
||||
challengeType: 20
|
||||
dashedName: step-25
|
||||
dashedName: step-26
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -45,11 +45,11 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if not isinstance(level, str):
|
||||
raise TypeError("'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self.name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
@@ -69,14 +69,16 @@ class Employee:
|
||||
raise TypeError("'name' must be a string.")
|
||||
self._name = new_name
|
||||
print(f"'name' updated to '{self.name}'.")
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
+12
-14
@@ -1,13 +1,13 @@
|
||||
---
|
||||
id: 68c9c3aa714bc326e026b826
|
||||
title: Step 26
|
||||
title: Step 30
|
||||
challengeType: 20
|
||||
dashedName: step-26
|
||||
dashedName: step-30
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
The new level cannot be set without checking if it's a valid level. At the beginning of your setter, create an `if` statement that raises a `ValueError` when `new_level` is not a key of `Employee._base_salaries`.
|
||||
The new level cannot be set without checking if it's a valid level. After the `isinstance` check, create an `if` statement that raises a `ValueError` when `new_level` is not a key of `Employee._base_salaries`.
|
||||
|
||||
For the error message, use `Invalid value '{new_level}' for 'level' attribute.`, where `{new_level}` should be replaced by the argument passed to the setter.
|
||||
|
||||
@@ -16,7 +16,7 @@ For the error message, use `Invalid value '{new_level}' for 'level' attribute.`,
|
||||
You should have an `if` statement inside your `level` setter.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[0]`)) })
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[1]`)) })
|
||||
```
|
||||
|
||||
When `new_level` is not a key of `Employee._base_salaries`, you should raise a `ValueError` with the message `Invalid value '{new_level}' for 'level' attribute.`, where `{new_level}` should be replaced by the argument passed to the setter.
|
||||
@@ -60,12 +60,8 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
@@ -88,13 +84,15 @@ class Employee:
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
--fcc-editable-region--
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
|
||||
self._level = new_level
|
||||
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
self._level = new_level
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
+21
-14
@@ -1,22 +1,24 @@
|
||||
---
|
||||
id: 68c9cab4b1118da59eecfc56
|
||||
title: Step 27
|
||||
title: Step 31
|
||||
challengeType: 20
|
||||
dashedName: step-27
|
||||
dashedName: step-31
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After the existing `if` statement, create another one to raise a `ValueError` when `new_level` is already the selected level.
|
||||
After the existing `if` statements, create another one to raise a `ValueError` when `new_level` is already the selected level.
|
||||
|
||||
Note that `_level` doesn't exist yet during initialization, so use `hasattr(self, '_level')` to check if it exists before comparing. This avoids an `AttributeError` when the object is first created.
|
||||
|
||||
For the message, use `'{level}' is already the selected level.`, where `{level}` should be replaced by the current level.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a second `if` statement inside your `level` setter.
|
||||
You should have a third `if` statement inside your `level` setter.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[1]`)) })
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[2]`)) })
|
||||
```
|
||||
|
||||
When `new_level` is equal to `self.level`, you should raise a `ValueError` with the message `'{level}' is already the selected level.`, where `{level}` should be replaced by the current level.
|
||||
@@ -33,6 +35,12 @@ When `new_level` is equal to `self.level`, you should raise a `ValueError` with
|
||||
`) })
|
||||
```
|
||||
|
||||
Your `if` statement should use `hasattr(self, '_level')` to check if `_level` exists before comparing.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[2].find_conditions()[0].is_equivalent("hasattr(self, '_level') and new_level == self.level")`)) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
@@ -47,12 +55,8 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
@@ -75,16 +79,19 @@ class Employee:
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
--fcc-editable-region--
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
--fcc-editable-region--
|
||||
|
||||
|
||||
--fcc-editable-region--
|
||||
self._level = new_level
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
+21
-14
@@ -1,20 +1,28 @@
|
||||
---
|
||||
id: 68ca758f8160b11757f877ae
|
||||
title: Step 28
|
||||
title: Step 32
|
||||
challengeType: 20
|
||||
dashedName: step-28
|
||||
dashedName: step-32
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Finally, create a third `if` statement that raises a `ValueError` with the message `Cannot change to lower level.` when the base salary of the new level is less than the base salary of the current level.
|
||||
Finally, create a fourth `if` statement that raises a `ValueError` with the message `Cannot change to lower level.` when the base salary of the new level is less than the base salary of the current level.
|
||||
|
||||
Use `hasattr(self, '_level')` to avoid an `AttributeError` during initialization.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have a third `if` statement inside your `level` setter.
|
||||
You should have a fourth `if` statement inside your `level` setter.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[2]`)) })
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[3]`)) })
|
||||
```
|
||||
|
||||
Your `if` statement should use `hasattr(self, '_level')` to check if `_level` exists before comparing.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[3].find_conditions()[0].is_equivalent("hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]")`)) })
|
||||
```
|
||||
|
||||
When `new_level` is lower than `self.level`, you should raise a `ValueError` with the message `Cannot change to lower level.`
|
||||
@@ -57,12 +65,8 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
@@ -85,17 +89,20 @@ class Employee:
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
--fcc-editable-region--
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
self._level = new_level
|
||||
|
||||
--fcc-editable-region--
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
+14
-15
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68caa8fb3bed34833ef24aee
|
||||
title: Step 29
|
||||
title: Step 33
|
||||
challengeType: 20
|
||||
dashedName: step-29
|
||||
dashedName: step-33
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -17,9 +17,9 @@ You should set `self._salary` to the base salary for the new level.
|
||||
|
||||
```js
|
||||
({ test: () => runPython(`
|
||||
emp = Employee('Frank', 'trainee')
|
||||
new_levels = ['junior', 'mid-level', 'senior']
|
||||
for new_level in new_levels:
|
||||
emp = Employee('Frank', 'trainee')
|
||||
new_levels = ['junior', 'mid-level', 'senior']
|
||||
for new_level in new_levels:
|
||||
emp.level = new_level
|
||||
assert emp.salary == Employee._base_salaries.get(new_level)
|
||||
`) })
|
||||
@@ -39,12 +39,8 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
@@ -70,16 +66,19 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
--fcc-editable-region--
|
||||
|
||||
self._level = new_level
|
||||
--fcc-editable-region--
|
||||
self._level = new_level
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
+11
-12
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68caa9fb6f1602975e41b051
|
||||
title: Step 30
|
||||
title: Step 34
|
||||
challengeType: 20
|
||||
dashedName: step-30
|
||||
dashedName: step-34
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -45,12 +45,8 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
@@ -76,17 +72,20 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
self._salary = Employee._base_salaries[new_level]
|
||||
self._level = new_level
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
+9
-11
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68caaaef4afb18aab8a684d4
|
||||
title: Step 31
|
||||
title: Step 35
|
||||
challengeType: 20
|
||||
dashedName: step-31
|
||||
dashedName: step-35
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -33,12 +33,8 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
@@ -64,12 +60,14 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
print(f"'{self.name}' promoted to '{new_level}'.")
|
||||
self._salary = Employee._base_salaries[new_level]
|
||||
self._level = new_level
|
||||
|
||||
+11
-12
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68caacb0f4311cc9be9a2132
|
||||
title: Step 32
|
||||
title: Step 36
|
||||
challengeType: 20
|
||||
dashedName: step-32
|
||||
dashedName: step-36
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -66,12 +66,8 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
@@ -97,20 +93,23 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
print(f"'{self.name}' promoted to '{new_level}'.")
|
||||
self._salary = Employee._base_salaries[new_level]
|
||||
self._level = new_level
|
||||
--fcc-editable-region--
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
|
||||
|
||||
+13
-15
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68caaf1e590806f0b87f5922
|
||||
title: Step 33
|
||||
title: Step 38
|
||||
challengeType: 20
|
||||
dashedName: step-33
|
||||
dashedName: step-38
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -66,13 +66,9 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
self.name = name
|
||||
self.level = level
|
||||
self.salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
@@ -97,12 +93,14 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
print(f"'{self.name}' promoted to '{new_level}'.")
|
||||
self._salary = Employee._base_salaries[new_level]
|
||||
self._level = new_level
|
||||
@@ -110,18 +108,18 @@ class Employee:
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
--fcc-editable-region--
|
||||
|
||||
@salary.setter
|
||||
def salary(self, new_salary):
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
self._salary = new_salary
|
||||
print(f'Salary updated to ${self.salary}.')
|
||||
--fcc-editable-region--
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
|
||||
charlie_brown.level = 'junior'
|
||||
|
||||
```
|
||||
|
||||
+21
-18
@@ -1,13 +1,13 @@
|
||||
---
|
||||
id: 68cab02fd80a91042c0165b8
|
||||
title: Step 34
|
||||
title: Step 39
|
||||
challengeType: 20
|
||||
dashedName: step-34
|
||||
dashedName: step-39
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
After your existing `if` statement, create another one for when the new salary is less than the base salary for the current level.
|
||||
After your existing `if` statement, create another one for when the new salary is less than the base salary for the current level. Use `hasattr(self, '_level')` to avoid an `AttributeError` during initialization.
|
||||
|
||||
Inside the `if` statement, raise a `ValueError` with the message `Salary must be higher than minimum salary $` followed by the base salary for the current level and a period.
|
||||
|
||||
@@ -19,6 +19,12 @@ You should have a second `if` statement in your `salary` setter.
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("salary")[1].find_ifs()[1]`)) })
|
||||
```
|
||||
|
||||
Your `if` statement should use `hasattr(self, '_level')` to check if `_level` exists before comparing.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("salary")[1].find_ifs()[1].find_conditions()[0].is_equivalent("hasattr(self, '_level') and new_salary < Employee._base_salaries[self.level]")`)) })
|
||||
```
|
||||
|
||||
When the new salary is less than the base salary for the current level, you should raise a `ValueError` with the message `Salary must be higher than minimum salary $` followed by the base salary for the current level and a period.
|
||||
|
||||
```js
|
||||
@@ -70,13 +76,9 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
self.name = name
|
||||
self.level = level
|
||||
self.salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
@@ -101,34 +103,35 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
print(f"'{self.name}' promoted to '{new_level}'.")
|
||||
self._salary = Employee._base_salaries[new_level]
|
||||
self.salary = Employee._base_salaries[new_level]
|
||||
self._level = new_level
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
--fcc-editable-region--
|
||||
|
||||
@salary.setter
|
||||
def salary(self, new_salary):
|
||||
if not isinstance(new_salary, (int, float)):
|
||||
raise TypeError("'salary' must be a number.")
|
||||
--fcc-editable-region--
|
||||
|
||||
|
||||
--fcc-editable-region--
|
||||
self._salary = new_salary
|
||||
print(f'Salary updated to ${self.salary}.')
|
||||
--fcc-editable-region--
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
|
||||
charlie_brown.level = 'junior'
|
||||
|
||||
```
|
||||
|
||||
+20
-25
@@ -1,8 +1,8 @@
|
||||
---
|
||||
id: 68cab17ac51b861a8458c42d
|
||||
title: Step 35
|
||||
title: Step 40
|
||||
challengeType: 20
|
||||
dashedName: step-35
|
||||
dashedName: step-40
|
||||
---
|
||||
|
||||
# --description--
|
||||
@@ -50,13 +50,9 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
self.name = name
|
||||
self.level = level
|
||||
self.salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
@@ -81,12 +77,14 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
print(f"'{self.name}' promoted to '{new_level}'.")
|
||||
--fcc-editable-region--
|
||||
self._salary = Employee._base_salaries[new_level]
|
||||
@@ -101,12 +99,11 @@ class Employee:
|
||||
def salary(self, new_salary):
|
||||
if not isinstance(new_salary, (int, float)):
|
||||
raise TypeError("'salary' must be a number.")
|
||||
if new_salary <= Employee._base_salaries[self.level]:
|
||||
if hasattr(self, '_level') and new_salary < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f'Salary must be higher than minimum salary ${Employee._base_salaries[self.level]}.')
|
||||
self._salary = new_salary
|
||||
print(f'Salary updated to ${self.salary}.')
|
||||
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
@@ -125,13 +122,9 @@ class Employee:
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
self.name = name
|
||||
self.level = level
|
||||
self.salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
@@ -156,12 +149,14 @@ class Employee:
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if new_level == self.level:
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f"Cannot change to lower level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
print(f"'{self.name}' promoted to '{new_level}'.")
|
||||
self.salary = Employee._base_salaries[new_level]
|
||||
self._level = new_level
|
||||
@@ -174,7 +169,7 @@ class Employee:
|
||||
def salary(self, new_salary):
|
||||
if not isinstance(new_salary, (int, float)):
|
||||
raise TypeError("'salary' must be a number.")
|
||||
if new_salary <= Employee._base_salaries[self.level]:
|
||||
if hasattr(self, '_level') and new_salary < Employee._base_salaries[self.level]:
|
||||
raise ValueError(f'Salary must be higher than minimum salary ${Employee._base_salaries[self.level]}.')
|
||||
self._salary = new_salary
|
||||
print(f'Salary updated to ${self.salary}.')
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
---
|
||||
id: 69b014adbc624861e6ff3dd1
|
||||
title: Step 21
|
||||
challengeType: 20
|
||||
dashedName: step-21
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the `name` setter is created, update `__init__` to use `self.name = name` instead of `self._name = name`. This delegates `name` assignment through the setter, and validation will be added to it in the next step.
|
||||
|
||||
Also, adjust the `if` condition to only check `level`, and update the `TypeError` message accordingly:
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `__init__` method should use `self.name = name` instead of `self._name = name`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_function("__init__").has_stmt("self.name = name")`)) })
|
||||
```
|
||||
|
||||
Your `__init__` method should only check `isinstance(level, str)` and update the `TypeError` message accordingly.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_function("__init__").find_if("not isinstance(level, str)").find_body().has_stmt("raise TypeError(\\"'level' attribute must be of type 'str'.\\")")`)) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
class Employee:
|
||||
_base_salaries = {
|
||||
'trainee': 1000,
|
||||
'junior': 2000,
|
||||
'mid-level': 3000,
|
||||
'senior': 4000,
|
||||
}
|
||||
def __init__(self, name, level):
|
||||
--fcc-editable-region--
|
||||
if not (isinstance(name, str) and isinstance(level, str)):
|
||||
raise TypeError("'name' and 'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self._name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
--fcc-editable-region--
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
|
||||
def __repr__(self):
|
||||
return f"Employee('{self.name}', '{self.level}')"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
self._name = new_name
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
```
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
---
|
||||
id: 69b023541591abde576613db
|
||||
title: Step 27
|
||||
challengeType: 20
|
||||
dashedName: step-27
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the `level` setter is created, update `__init__` to use `self.level = level` instead of `self._level = level`. This delegates `level` assignment through the setter, and validation will be added to it in the next step.
|
||||
|
||||
Also, remove the `if not isinstance(level, str)` check from `__init__` since the setter will handle that validation in the next step.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `__init__` method should use `self.level = level` instead of `self._level = level`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_function("__init__").has_stmt("self.level = level")`)) })
|
||||
```
|
||||
|
||||
Your `__init__` method should not contain the `isinstance(level, str)` check.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`not _Node(_code).find_class("Employee").find_function("__init__").find_if("not isinstance(level, str)").find_body().has_stmt("raise TypeError(\\"'level' attribute must be of type 'str'.\\")")`)) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
class Employee:
|
||||
_base_salaries = {
|
||||
'trainee': 1000,
|
||||
'junior': 2000,
|
||||
'mid-level': 3000,
|
||||
'senior': 4000,
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
--fcc-editable-region--
|
||||
if not isinstance(level, str):
|
||||
raise TypeError("'level' attribute must be of type 'str'.")
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self.name = name
|
||||
self._level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
--fcc-editable-region--
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
|
||||
def __repr__(self):
|
||||
return f"Employee('{self.name}', '{self.level}')"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
if not isinstance(new_name, str):
|
||||
raise TypeError("'name' must be a string.")
|
||||
self._name = new_name
|
||||
print(f"'name' updated to '{self.name}'.")
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
self._level = new_level
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
```
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
---
|
||||
id: 69c0dc6914ac0434f0cc52b7
|
||||
title: Step 28
|
||||
challengeType: 20
|
||||
dashedName: step-28
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
To ensure that `new_level` is the right type, create an `if` statement that raises a `TypeError` with the message `'level' must be a string.` when `new_level` is not an instance of `str`.
|
||||
|
||||
# --hints--
|
||||
|
||||
You should have an `if` statement inside your `level` setter.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_functions("level")[1].find_ifs()[0]`)) })
|
||||
```
|
||||
|
||||
You should raise a `TypeError` with the message `'level' must be a string.` when `new_level` is not an instance of `str`.
|
||||
|
||||
```js
|
||||
({ test: () => runPython(`
|
||||
emp = Employee('Frank', 'trainee')
|
||||
non_levels = [0, True, []]
|
||||
for i in non_levels:
|
||||
try:
|
||||
emp.level = i
|
||||
except TypeError as e:
|
||||
assert str(e) == "'level' must be a string."
|
||||
else:
|
||||
assert False, "Expected to raise TypeError with non-string new_level"
|
||||
`) })
|
||||
```
|
||||
|
||||
You should not raise any exception when `new_level` is a string.
|
||||
|
||||
```js
|
||||
({ test: () => runPython(`
|
||||
emp = Employee('Frank', 'trainee')
|
||||
try:
|
||||
emp.level = "junior"
|
||||
except TypeError:
|
||||
assert False, "Expected not to raise TypeError with string new_level"
|
||||
`) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
class Employee:
|
||||
_base_salaries = {
|
||||
'trainee': 1000,
|
||||
'junior': 2000,
|
||||
'mid-level': 3000,
|
||||
'senior': 4000,
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
|
||||
def __repr__(self):
|
||||
return f"Employee('{self.name}', '{self.level}')"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
if not isinstance(new_name, str):
|
||||
raise TypeError("'name' must be a string.")
|
||||
self._name = new_name
|
||||
print(f"'name' updated to '{self.name}'.")
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
--fcc-editable-region--
|
||||
|
||||
--fcc-editable-region--
|
||||
self._level = new_level
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
```
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
---
|
||||
id: 69c0e73cc6f2cf16a453c69e
|
||||
title: Step 29
|
||||
challengeType: 20
|
||||
dashedName: step-29
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the `level` setter handles the validation for invalid levels, remove the `if level not in Employee._base_salaries` check from `__init__`. This will be handled by the setter in the next step.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `__init__` method should not contain the `level not in Employee._base_salaries` check.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`not _Node(_code).find_class("Employee").find_function("__init__").find_if("level not in Employee._base_salaries").find_body().has_stmt("raise ValueError(f\\"Invalid value '{level}' for 'level' attribute.\\")")`)) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
class Employee:
|
||||
_base_salaries = {
|
||||
'trainee': 1000,
|
||||
'junior': 2000,
|
||||
'mid-level': 3000,
|
||||
'senior': 4000,
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
--fcc-editable-region--
|
||||
if level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{level}' for 'level' attribute.")
|
||||
--fcc-editable-region--
|
||||
self.name = name
|
||||
self.level = level
|
||||
self._salary = Employee._base_salaries[level]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
|
||||
def __repr__(self):
|
||||
return f"Employee('{self.name}', '{self.level}')"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
if not isinstance(new_name, str):
|
||||
raise TypeError("'name' must be a string.")
|
||||
self._name = new_name
|
||||
print(f"'name' updated to '{self.name}'.")
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
self._level = new_level
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
```
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
---
|
||||
id: 69c2293ea0ecd3718984451b
|
||||
title: Step 37
|
||||
challengeType: 20
|
||||
dashedName: step-37
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
Now that the `salary` setter is created, update `__init__` to call it instead of assigning directly to `self._salary`. Change `self._salary = Employee._base_salaries[level]` to `self.salary = Employee._base_salaries[level]`.
|
||||
|
||||
# --hints--
|
||||
|
||||
Your `__init__` method should use `self.salary = Employee._base_salaries[level]` instead of `self._salary = Employee._base_salaries[level]`.
|
||||
|
||||
```js
|
||||
({ test: () => assert(runPython(`_Node(_code).find_class("Employee").find_function("__init__").has_stmt("self.salary = Employee._base_salaries[level]")`)) })
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```py
|
||||
class Employee:
|
||||
_base_salaries = {
|
||||
'trainee': 1000,
|
||||
'junior': 2000,
|
||||
'mid-level': 3000,
|
||||
'senior': 4000,
|
||||
}
|
||||
|
||||
def __init__(self, name, level):
|
||||
self.name = name
|
||||
self.level = level
|
||||
--fcc-editable-region--
|
||||
self._salary = Employee._base_salaries[level]
|
||||
--fcc-editable-region--
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name}: {self.level}'
|
||||
|
||||
def __repr__(self):
|
||||
return f"Employee('{self.name}', '{self.level}')"
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._name
|
||||
|
||||
@name.setter
|
||||
def name(self, new_name):
|
||||
if not isinstance(new_name, str):
|
||||
raise TypeError("'name' must be a string.")
|
||||
self._name = new_name
|
||||
print(f"'name' updated to '{self.name}'.")
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
return self._level
|
||||
|
||||
@level.setter
|
||||
def level(self, new_level):
|
||||
if not isinstance(new_level, str):
|
||||
raise TypeError("'level' must be a string.")
|
||||
if new_level not in Employee._base_salaries:
|
||||
raise ValueError(f"Invalid value '{new_level}' for 'level' attribute.")
|
||||
if hasattr(self, '_level') and new_level == self.level:
|
||||
raise ValueError(f"'{self.level}' is already the selected level.")
|
||||
if hasattr(self, '_level') and Employee._base_salaries[new_level] < Employee._base_salaries[self.level]:
|
||||
raise ValueError("Cannot change to lower level.")
|
||||
print(f"'{self.name}' promoted to '{new_level}'.")
|
||||
self._salary = Employee._base_salaries[new_level]
|
||||
self._level = new_level
|
||||
|
||||
@property
|
||||
def salary(self):
|
||||
return self._salary
|
||||
|
||||
@salary.setter
|
||||
def salary(self, new_salary):
|
||||
self._salary = new_salary
|
||||
print(f'Salary updated to ${self.salary}.')
|
||||
|
||||
charlie_brown = Employee('Charlie Brown', 'trainee')
|
||||
print(charlie_brown)
|
||||
print(f'Base salary: ${charlie_brown.salary}')
|
||||
|
||||
charlie_brown.level = 'junior'
|
||||
|
||||
```
|
||||
@@ -25,21 +25,26 @@
|
||||
{ "id": "68c9a1c241206043c81293d5", "title": "Step 18" },
|
||||
{ "id": "68c9a2c015ed7b54cf81e789", "title": "Step 19" },
|
||||
{ "id": "68c8002beb157fe47d2e7699", "title": "Step 20" },
|
||||
{ "id": "68c809c990f253912a9e9209", "title": "Step 21" },
|
||||
{ "id": "68c80b63ca4e5eadf1fac738", "title": "Step 22" },
|
||||
{ "id": "68c9a09163d4a42e9bc9b638", "title": "Step 23" },
|
||||
{ "id": "68c9a624fd54288f694ebdbf", "title": "Step 24" },
|
||||
{ "id": "68c9a72c9dab42a15ce6972b", "title": "Step 25" },
|
||||
{ "id": "68c9c3aa714bc326e026b826", "title": "Step 26" },
|
||||
{ "id": "68c9cab4b1118da59eecfc56", "title": "Step 27" },
|
||||
{ "id": "68ca758f8160b11757f877ae", "title": "Step 28" },
|
||||
{ "id": "68caa8fb3bed34833ef24aee", "title": "Step 29" },
|
||||
{ "id": "68caa9fb6f1602975e41b051", "title": "Step 30" },
|
||||
{ "id": "68caaaef4afb18aab8a684d4", "title": "Step 31" },
|
||||
{ "id": "68caacb0f4311cc9be9a2132", "title": "Step 32" },
|
||||
{ "id": "68caaf1e590806f0b87f5922", "title": "Step 33" },
|
||||
{ "id": "68cab02fd80a91042c0165b8", "title": "Step 34" },
|
||||
{ "id": "68cab17ac51b861a8458c42d", "title": "Step 35" }
|
||||
{ "id": "69b014adbc624861e6ff3dd1", "title": "Step 21" },
|
||||
{ "id": "68c809c990f253912a9e9209", "title": "Step 22" },
|
||||
{ "id": "68c80b63ca4e5eadf1fac738", "title": "Step 23" },
|
||||
{ "id": "68c9a09163d4a42e9bc9b638", "title": "Step 24" },
|
||||
{ "id": "68c9a624fd54288f694ebdbf", "title": "Step 25" },
|
||||
{ "id": "68c9a72c9dab42a15ce6972b", "title": "Step 26" },
|
||||
{ "id": "69b023541591abde576613db", "title": "Step 27" },
|
||||
{ "id": "69c0dc6914ac0434f0cc52b7", "title": "Step 28" },
|
||||
{ "id": "69c0e73cc6f2cf16a453c69e", "title": "Step 29" },
|
||||
{ "id": "68c9c3aa714bc326e026b826", "title": "Step 30" },
|
||||
{ "id": "68c9cab4b1118da59eecfc56", "title": "Step 31" },
|
||||
{ "id": "68ca758f8160b11757f877ae", "title": "Step 32" },
|
||||
{ "id": "68caa8fb3bed34833ef24aee", "title": "Step 33" },
|
||||
{ "id": "68caa9fb6f1602975e41b051", "title": "Step 34" },
|
||||
{ "id": "68caaaef4afb18aab8a684d4", "title": "Step 35" },
|
||||
{ "id": "68caacb0f4311cc9be9a2132", "title": "Step 36" },
|
||||
{ "id": "69c2293ea0ecd3718984451b", "title": "Step 37" },
|
||||
{ "id": "68caaf1e590806f0b87f5922", "title": "Step 38" },
|
||||
{ "id": "68cab02fd80a91042c0165b8", "title": "Step 39" },
|
||||
{ "id": "68cab17ac51b861a8458c42d", "title": "Step 40" }
|
||||
],
|
||||
"usesMultifileEditor": true,
|
||||
"hasEditableBoundaries": true
|
||||
|
||||
Reference in New Issue
Block a user