если еще - если код выглядит безобразно, какое-нибудь более чистое решение? - PullRequest
2 голосов
/ 05 мая 2010

У меня около 20 функций (is_func1, is_fucn2, is_func3 ...), возвращающих логическое значение

Я предполагаю, что есть только одна функция, которая возвращает true, и я хочу это!

Я делаю:

if is_func1(param1, param2):
    # I pass 1 to following
    abc(1) # I pass 1
    some_list.append(1)
elif is_func2(param1, param2):
    # I pass 2 to following
    abc(2) # I pass 1
    some_list.append(2)
...
.
.
elif is_func20(param1, param2):
...

Обратите внимание: param1 и param2 различны для каждого, abc и some_list принимают параметры в зависимости от функции.

Код выглядит большим, и в вызовах abc и some_list есть повторение, я могу получить этот логин в функции! но есть ли другое чистое решение?

Я могу подумать о том, чтобы поместить функции в структуру данных и цикл для их вызова.

Ответы [ 9 ]

4 голосов
/ 05 мая 2010

А как же

functionList = [is_func1, is_func2, ..., is_func20]
for index, func in enumerate(functionList):
    if(func(param1, param2)):
        abc(index+1)
        some_list.append(index+1)
        break
2 голосов
/ 05 мая 2010

Я могу подумать о том, чтобы поместить функции в структуру данных и цикл для их вызова.

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

Пример, похожий на ответ BlueRaja ,

# arg1, arg2 and ret can have any values on each record
data = ((isfunc1, arg1, arg2, ret),
 (isfunc2, arg1, arg2, ret),
 (isfunc3, arg1, arg2, ret),
  ...)

for d in data:
    if d[0](d[1], d[2]):
        abc(d[3])
        some_list.append(d[3])
        break
1 голос
/ 06 мая 2010

Я изменил ответ BlueRaja для разных параметров ...

function_list = {is_func01: (pa1, pa2, ...),
                 is_func02: (pa1, pa2, pa3, ...), 
                 ....
                 is_func20: (pa1, ...)}

for func, pa_list in function_list.items:
    if(func(*pa_list)):
        abc(pa_list_dependent_parameters)
        some_list.append(pa_list_dependent_parameters)
        break

Я не понимаю, почему это не должно работать.

1 голос
/ 05 мая 2010

Это хороший пример применения Схема цепочки ответственности .

Я знаю, как привести пример с объектами, а не с функциями, поэтому я сделаю это:

class HandleWithFunc1
   def __init__(self, otherHandler):
      self.otherHandler = otherHandler

   def Handle(param1, param2):
     if ( should I handle with func1? ):
          #Handle with func1
          return
     if otherHandler == None:
        raise "Nobody handled the call!"

     otherHandler.Handle(param1, param2)

class HandleWithFunc2:
   def __init__(self, otherHandler):
      self.otherHandler = otherHandler

   def Handle(param1, param2):
     if ( should I handle with func1? ):
          #Handle with func1
          return
     if otherHandler == None:
        raise "Nobody handled the call!"

     otherHandler.Handle(param1, param2)

Итак, вы создаете все свои классы как цепочки:

handle = HandleWithFunc1(HandleWithFunc2())

тогда:

handle.Handle(param1, param2)

Этот код подвержен рефакторингу, здесь только для иллюстрации использования

1 голос
/ 05 мая 2010

Попробуйте это:

value = 1 if is_func1(param1, param2) else \
        2 if is_func2(param1x, param2x) else \
        ... else \
        20 if is_func20(param1z, param2z) else 0

abc(value)
some_list.append(value)

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

Основной смысл состоит в том, чтобы создать единственное значение, которое соответствует вызываемой функции (1 для is_func1, 2 для is_func2 и т. Д.), А затем использовать это значение в функциях abc и some_list.append. Продолжая то, что я смог прочитать об оценке булевых выражений Python, это должно должным образом замкнуть оценку так, чтобы функции перестали вызываться, как только вычисляется значение true.

1 голос
/ 05 мая 2010

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

0 голосов
/ 05 мая 2010

Я не уверен, что будет чище, но я думаю, что это довольно интересное решение.

Прежде всего вы должны определить новую функцию, пусть она будет semi_func, которая вызовет abc и some_list.append сделает код СУХИМ.

Затем установите новую переменную, которая будет действовать как двоичный результат всех логических функций, так что is_func1 это 20-й бит, is_func2 это 19-й и так далее 32 бита целочисленного типа должно быть достаточно для обработки всех 20 результатов.

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

result = is_func1(param1, param2) << 1
result = (result | is_func2(param1, param2)) << 1
...
result = (result | is_func20(param1, param2))

Для облегчения доступа определите новые константы, такие как

IS_FUNC20_TRUE = 1
IS_FUNC19_TRUE = 2
IS_FUNC18_TRUE = 4
... values should be powers of 2

И в конце используйте оператор switch / sase для вызова semi_func.

0 голосов
/ 05 мая 2010

Я знаю, что меня унизят за оффтоп, но все же. Если вы найдете что-то, что можно сделать с помощью стандартных управляющих конструкций, то вам нужно использовать другой язык, такой как Common Lisp, который допускает макросы, фактически позволяющий создавать ваши собственные управляющие конструкции. (Недавно обнаружив анафорические макросы, я просто рекомендую это.)

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

В любом случае, в Python, я думаю, вы должны согласиться со списком функций и циклом.

0 голосов
/ 05 мая 2010

Я раньше не использовал python, но можете ли вы ссылаться на функции по переменной?

Если это так, вы можете создать перечисление с записями, представляющими каждую функцию, протестировать все функции в цикле и установить для переменной перечисление «истинной» функции.

Затем вы можете сделать оператор switch для перечисления.

Тем не менее, это не сильно «очистит» код: когда у вас есть n опций и вам нужно перейти к правильному, вам понадобится n блоков кода для его обработки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...