8

У меня есть тема для обсуждения. У меня есть фрагмент кода с 24 ifs/elifs. Операция - это мой собственный класс, который представляет функциональность, похожую на Enum. Вот фрагмент кода:Слишком много операторов if

if operation == Operation.START: 
    strategy = strategy_objects.StartObject() 
elif operation == Operation.STOP: 
    strategy = strategy_objects.StopObject() 
elif operation == Operation.STATUS: 
    strategy = strategy_objects.StatusObject() 
(...) 

У меня есть проблемы с точки зрения удобочитаемости. Лучше изменить его на 24 класса и использовать полиморфизм? Я не уверен, что это сделает мой код работоспособным ... С одной стороны, эти ifs довольно понятны, и с ними не должно быть трудно следовать, с другой стороны, слишком много ifs.

Мой вопрос довольно общий, однако я пишу код в python, поэтому я не могу использовать конструкции типа switch.

Как вы думаете?

UPDATE:

Одна важная вещь в том, что StartObject(), StopObject() и StatusObject() являются конструкторами, и я хотел присвоить объект стратегии эталонным.

+0

'case' заявление, вместо этого? что или имеют массив ссылок на методы для вызова динамически, например. любой эквивалент python 'array_of_methods [operation]()' будет ... –

+3

Марк, python не имеет операторов switch/case. https://www.python.org/dev/peps/pep-3103/ – Stiffo

ответ

12

Возможно, вы можете использовать словарь. ссылки магазин словари, а это значит, функции вполне жизнеспособны использовать, например, так:.

operationFuncs = { 
    Operation.START: strategy_objects.StartObject 
    Operation.STOP: strategy_objects.StopObject 
    Operation.STATUS: strategy_objects.StatusObject 
    (...)     
} 

Это хорошо, чтобы иметь операцию по умолчанию только в том случае, поэтому, когда вы запустите его использовать try except и обрабатывать исключения (т.е. эквивалент вашей статьи else)

try: 
    strategy = operationFuncs[operation]() 
except KeyError: 
    strategy = strategy_objects.DefaultObject() 

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

strategy = operationFuncs.get(operation(), DefaultObject()) 

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

0

Если Operation.START, и т.д., hashable, вы можете использовать словарь с ключами как условие и значения, как функции для вызова, например, -

d = {Operation.START: strategy_objects.StartObject , 
    Operation.STOP: strategy_objects.StopObject, 
    Operation.STATUS: strategy_objects.StatusObject} 

И тогда вы можете сделать это поиск по словарю и вызовите функция, пример -

d[operation]() 
3

Python эквивалент оператора switch заключается в использовании словаря. По сути, вы можете хранить ключи так же, как и случаи, а значения - это то, что вызывается для этого конкретного случая.Поскольку функции являются объектами в Python вы можете хранить их в качестве словарных значений:

operation_dispatcher = { 
    Operation.START: strategy_objects.StartObject, 
    Operation.STOP: strategy_objects.StopObject, 
} 

, которые затем могут быть использованы следующим образом:

try: 
    strategy = operation_dispatcher[operation] #fetch the strategy 
except KeyError: 
    strategy = default #this deals with the else-case (if you have one) 
strategy() #call if needed 

Или более кратко:

strategy = operation_dispatcher.get(operation, default) 
strategy() #call if needed 

Это может потенциально масштабируется намного лучше, чем беспорядок операторов if-else. Обратите внимание: если у вас нет другого дела, с которым вы можете иметь дело, вы можете просто использовать словарь напрямую с operation_dispatcher[operation].

-1

Вот извращается переключатель/случай сделано с использованием словарей:

Например:

# define the function blocks 
def start(): 
    strategy = strategy_objects.StartObject() 

def stop(): 
    strategy = strategy_objects.StopObject() 

def status(): 
    strategy = strategy_objects.StatusObject() 

# map the inputs to the function blocks 
options = {"start" : start, 
      "stop" : stop, 
      "status" : status, 

} 

Тогда эквивалентный блок переключателя вызывается:

options["string"]() 
+1

Но «стратегия» будет локальной для каждой из этих небольших функций и не будет видна в области, где вы выполняете 'options [" string «]()'. – Kevin

1

Вы можете использовать некоторые интроспекции с getattr:

strategy = getattr(strategy_objects, "%sObject" % operation.capitalize())() 

Предположим, что операция «СТАТУС», она будет заглавной как «Статус», а затем добавлена ​​в «Объект», давая «StatusObject». Затем метод StatusObject будет вызываться на strategy_objects, катастрофически катастрофически, если этот атрибут не существует или если он не может быть вызван. :) (I.e. добавляет обработку ошибок.)

Решение словаря, вероятно, более гибкое.

+0

Проверка класса существует с hasattr (...) будет эквивалент KeyError в решении dictionnary. –

2

Вы можете попробовать что-то вроде this.

Например:

def chooseStrategy(op): 
    return { 
     Operation.START: strategy_objects.StartObject 
     Operation.STOP: strategy_objects.StopObject 
    }.get(op, strategy_objects.DefaultValue) 

Вызов его как этот

strategy = chooseStrategy(operation)() 

Этот метод имеет преимущество предоставления значения по умолчанию (например, окончательный другое заявление). Конечно, если вам нужно только использовать эту логику решения в одном месте в вашем коде, вы всегда можете использовать стратегию = dictionary.get (op, default) без функции.

+0

Вам не хватает вызова. 'strategy = selectStrategy (operation)()' – Brobin

+0

Спасибо! Я пропустил, что он назвал выбранную стратегию. Я редактировал свой пост. – weirdev

 Смежные вопросы

  • Нет связанных вопросов^_^