Workshop workshop-salary-tracker, step-39; Understanding undersored attributes

Tell us what’s happening:

I was struggling with this step.
Finally, with the help from a forum topic, the test environment accepted this code and I passes the workshop:

    def salary(self, new_salary):
        if not isinstance(new_salary, (int, float)):
            raise TypeError("'salary' must be a number.")
        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}.')

What happened to me when trying to solve:

I tried Socrates:


Therefore I found out '_level' is preferred over 'level'.

I did it. I could not pass. So I used that help again:

So I split my if statements.. I could not pass. So I used that help again:

It tells me that do not split ifstatements.

Q1. I know Socrates is in beta. But I really want to know if the directions have any merit? I am a learner and should be ready for things to happen to me and learn from them. I see Hints here that to my opinion they do not match. Please explain about what you saw here.

Q2. What is the real difference in actual conditions to use ‘level’ instead of ‘_level’ ? (I already know that a setter gives me the benefit of checking the values.)

P.S.: In a code related to setter, it (guideline) expected me to use getter (can’t remember the step number):

if hasattr(self, '_level') and (new_salary < Employee._base_salaries[self.level]):
# not "_level" like: Employee._base_salaries[self._level]):

So, using the getter is EnforcedBySituation?/Useful?/Readability?/Necessary?/

Q3. In the code above, I have this in mind that if the first conditions fails, the second will also raise an exception. If self does not have a ‘_level’ attribute, does the python interpreter checks the second condition or just exits because there is an “and” operator and it will be finally “False”?
If not (in general terms and not just here) is it a good practice to use sinngle if instead of a nested one? Always?

Q4. In the code above, both ‘_level’ and ‘level’ are present. For which reasons?

Lesson URL

Hi @reThinker,

Socrates is not giving helpful advice here. Would you be interested in creating a GitHub Issue for this?

Please review again this theory lecture: Understanding Object Oriented Programming and Encapsulation - What are Getters and Setters | Learn | freeCodeCamp.org.

When the first condition in an if statement fails, it short-circuits and exits immediately.

I hope this helps to answer your questions. Sorry about the confusion created by Socrates.

Happy coding

Maybe Q4 was not seen. Yeah? :grinning_face_with_smiling_eyes:

Dear @dhess, Considering my Q2 question, I read this - though it is part of the course - again. Still not sure about

My intention is getting valuable lessons here, and getting the best of them. So let me say that Q2 is not answered.

…So, using the getter is which one? EnforcedBySituation? /Useful?/ ReadabilityMaker? /Necessary?/

Although, I still did not understand this: May be Q4 is related to these things too.
Q2. What is the real difference in actual conditions to use ‘level’ instead of ‘_level’ ? (I already know that a setter gives me the benefit of checking the values.) Why the getter is so emphasized? Why in the code are both of them used?

_level is a private attribute created the first time its setter is triggered in __init__.

The only time you should use _level is when you’re checking to see if it exists yet.

Each time you use level in your code, it triggers either the getter or setter to get or set _level.