I've seen a code on a project and would like to know how to write a code with less statements.
Here is the code:
if not self.test_done:
phase = "Test"
else:
if self.need_video and not self.video_sent:
phase = 'Video'
else:
if not self.screening1_made and not self.screening2_made:
phase = 'Screening 1'
else:
if ( self.screening1_made and not self.screening2_made ) or not self.passed_screening:
phase = 'Screening 2'
else:
if not self.passed_phase1:
phase = 'Interview 1'
else:
if not self.passed_phase2:
phase = 'Interview 2'
else:
if not self.passed_phase3:
phase = 'Interview 3'
else:
if not self.got_offer:
phase = 'Waiting offer decision'
else:
if self.accepted_offer is None:
phase = 'Waiting decision from candidate'
elif self.accepted_offer == "Accepted":
phase = 'Accepted offer'
elif self.accepted_offer == "Declined":
phase = 'Declined offer'
What would be best practices to avoid nested if statements?
CodePudding user response:
You can extract it to the method and early return, also you can use a dictionary lookup to get your output.
OFFER = {
None: "Waiting decision from candidate",
"Accepted": "Accepted offer",
"Declined": "Declined offer",
}
def some_function_name(self):
if not self.test_done:
return "Test"
if self.need_video and not self.video_sent:
return "Video"
if not self.screening1_made and not self.screening2_made:
return "Screening 1"
if (self.screening1_made and not self.screening2_made) or not self.passed_screening:
return "Screening 2"
if not self.passed_phase1:
return "Interview 1"
if not self.passed_phase2:
return "Interview 2"
if not self.passed_phase3:
return "Interview 3"
if not self.got_offer:
return "Waiting offer decision"
return OFFER.get(self.accepted_offer, None)
CodePudding user response:
This smells to me like a state machine. A "switch - case" construct is often used when evaluating state machines, and while python doesn't currently have that exact feature yet (3.10 will introduce match: case
), A list of elif
's should do the trick just fine:
if not self.test_done:
phase = "Test"
elif self.need_video and not self.video_sent:
phase = 'Video'
elif self.need_video and not self.video_sent:
phase = 'Video'
elif not self.screening1_made and not self.screening2_made:
phase = 'Screening 1'
elif ( self.screening1_made and not self.screening2_made ) or not self.passed_screening:
phase = 'Screening 2'
elif not self.passed_phase1:
phase = 'Interview 1'
elif not self.passed_phase2:
phase = 'Interview 2'
elif not self.passed_phase3:
phase = 'Interview 3'
elif not self.got_offer:
phase = 'Waiting offer decision'
elif self.accepted_offer is None:
phase = 'Waiting decision from candidate'
elif self.accepted_offer == "Accepted":
phase = 'Accepted offer'
elif self.accepted_offer == "Declined":
phase = 'Declined offer
flattened it's not so bad to look at, and you probably won't find a significantly more elegant solution without changing how you track all the conditionals.
CodePudding user response:
You can use lambda to run expressions. In the example below, we itterate through the list of tuples, containing lambda expressions and strings. When we find a lambda expression that is true, we break out of the loop.
x = 1
expressions = [
(lambda: x == 0, 'X is equal to 0'),
(lambda: x == 1, 'X is equal to 1'),
(lambda: x == 2, 'X is equal to 2'),
]
phrase = 'No result found'
for item in expressions:
expression = item[0]
text = item[1]
if expression():
phrase = text
break
print(phrase)
This is the result.
X is equal to 1
CodePudding user response:
You should refactor your program. Here's a rough Interview class and related objects, which includes a basic dictionary for event names and number of rounds.
class InterviewEvent:
def __init__(self, event_id, event_name, total_rounds) -> None:
self.event_id: int = event_id
self.event_name: str = event_name
self.total_rounds: int = total_rounds
self.competed_rounds: int = 0
self.completed: bool = False
class Interview:
"""Interview class to track interview progress.
"""
def __init__(self, expected_workflow: dict = None):
self.events = []
self.current_event: InterviewEvent = None
if expected_workflow:
self.__init_events(expected_workflow)
def __init_events(self, wf: dict) -> None:
"""Populate events list from workflow dictionary."""
self.events = [InterviewEvent(i, k, v) for i, (k, v) in enumerate(wf.items())]
# Set current event
self.current_event = self.events[0]
def completed_event_round(self, title, round_number):
"""Update round number for event. If complete, increment
to next round or next event in workflow.
"""
for event in self.events:
if event.event_name.lower() == title.lower():
if event.competed_rounds < round_number:
event.competed_rounds = round_number
# Mark event completed if completed rounds equals total rounds.
if event.competed_rounds == event.total_rounds:
event.completed = True
if event.completed:
# Increment current event by 1.
self.current_event = self.events[event.event_id 1]
def __event_attrs(self, e: InterviewEvent) -> str:
return "\n".join([f"{k}: {v}" for k, v in e.__dict__.items()])
@property
def view_current(self):
print(self.__event_attrs(self.current_event))
@property
def remaining_events(self):
return [e for e in self.events if not e.completed]
@property
def view_remaining_events(self):
events_remaining = self.remaining_events
if events_remaining:
print("\n\n".join([self.__event_attrs(e) for e in events_remaining]))
@property
def event_ids(self):
"""Return all current event IDs."""
return [e.event_id for e in self.events]
@property
def event_names(self):
"""Return all current event names."""
return [e.event_name for e in self.events]
# Dictionary of event names and number of rounds.
workflow_rounds = dict(
Test = 1,
Video = 1,
Screening = 2,
Interview = 3,
)
View events that are not complete.
interview.view_remaining_events
Output:
event_id: 0
event_name: Test
total_rounds: 1
competed_rounds: 0
completed: False
event_id: 1
event_name: Video
total_rounds: 1
competed_rounds: 0
completed: False
event_id: 2
event_name: Screening
total_rounds: 2
competed_rounds: 0
completed: False
event_id: 3
event_name: Interview
total_rounds: 3
competed_rounds: 0
completed: False
View current event
interview.view_current
Output:
event_id: 0
event_name: Test
total_rounds: 1
competed_rounds: 0
completed: False
Mark first Test round as complete
interview.completed_event_round(title = "Test", round_number = 1)
Again, view events that are not complete.
interview.view_remaining_events
Output:
event_id: 1
event_name: Video
total_rounds: 1
competed_rounds: 0
completed: False
event_id: 2
event_name: Screening
total_rounds: 2
competed_rounds: 0
completed: False
event_id: 3
event_name: Interview
total_rounds: 3
competed_rounds: 0
completed: False
Finally, view current event
interview.view_current
Output:
event_id: 1
event_name: Video
total_rounds: 1
competed_rounds: 0
completed: False