Улучшите код python с помощью множества операторов if

#python #if-statement #conditional-statements

Вопрос:

Я видел код в проекте и хотел бы знать, как написать код с меньшим количеством операторов.

Вот код:

     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'
 

Каковы были бы рекомендации по предотвращению вложенных операторов if?

Комментарии:

1. Используйте словарь.

2. Вы можете исправить глубокую вложенность с elif помощью s вместо большинства if s. Поскольку вы тестируете разные условия на всех этих тестах, я не уверен, что будет какой-либо хороший способ избежать их.

3. Не словарь (или какое-либо сопоставление, если на то пошло), эти условия не являются хорошими ключами.

Ответ №1:

Вы можете извлечь его в метод и досрочно вернуть, также вы можете использовать поиск по словарю для получения выходных данных.

 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)
 

Ответ №2:

Для меня это пахнет государственной машиной. Конструкция «случай переключения» часто используется при оценке конечных автоматов, и, хотя в настоящее время python еще не имеет этой точной функции (3.10 будет представлен match: case ), список elif » s » должен отлично справляться с этой задачей:

 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
 

сглаженный, на него не так уж плохо смотреть, и вы, вероятно, не найдете значительно более элегантного решения, не изменив способ отслеживания всех условий.

Ответ №3:

Вы можете использовать лямбда-код для выполнения выражений. В приведенном ниже примере мы просматриваем список кортежей, содержащих лямбда-выражения и строки. Когда мы находим истинное лямбда-выражение, мы выходим из цикла.

 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)
 

Таков результат.

 X is equal to 1
 

Ответ №4:

Вам следует провести рефакторинг вашей программы. Вот примерный класс интервью и связанные с ним объекты, который включает в себя базовый словарь для названий событий и количества раундов.

 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("nn".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,
)
 

Просмотр событий, которые не завершены.

 interview.view_remaining_events
 

Выход:

 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
 

Просмотр текущего события

 interview.view_current
 

Выход:

     event_id: 0
    event_name: Test
    total_rounds: 1
    competed_rounds: 0
    completed: False
 

Отметьте первый тестовый раунд как завершенный

 interview.completed_event_round(title = "Test", round_number = 1)
 

Опять же, просмотрите события, которые не являются завершенными.

 interview.view_remaining_events
 

Выход:

 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
 

Наконец, просмотрите текущее событие

 interview.view_current
 

Выход:

     event_id: 1
    event_name: Video
    total_rounds: 1
    competed_rounds: 0
    completed: False