2017-01-17 3 views
18

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

def Tank_Shape_Calcs(Tank_Shape, level, area, dish, radius, length, Strapping_Table, Tank_Number): 

    switcher = { 
     0: vertical.Vertical_Tank(level, area), 
     1: horiz.Horiz_Cylinder_Dished_Ends(dish, radius, level, length), 
     2: strapping.Calc_Strapped_Volume(Strapping_Table, level), 
     3: poly.Fifth_Poly_Calcs(Tank_Number) 
    } 
    return switcher.get(Tank_Shape, "ERROR: Tank type not valid") 

форма бака устанавливается в главном файле в цикле для каждого из резервуаров. Первый танк имеет Tank_Shape = 2, поэтому я ожидаю, что он выполнит функцию Calc_Strapped_Volume().

Я попытался проверить его, и функция переключателя определенно считывает Tank_Shape как 2. Также, если я изменил функции на строки, он напечатает правильную строку.

Проблема в том, что функции, похоже, выполняются последовательно, пока не будет вызвана правильная функция. Это приводит к ошибкам, так как данные, которые я использую, будут работать только с правильной функцией.

Есть ли способ выполнить только правильную функцию?

+5

Способ, которым вы структурировали свой код (вручную используя словарь lambdas для обработки нескольких действий, сочетая несколько разных аргументов, которые могут потребоваться или не понадобиться в зависимости от желаемого поведения и т. Д.) Предполагает, что вы новичок в Python , Я бы предложил вам опубликовать более полную копию вашего кода на codereview.stackexchange.com; некоторые пользователи могут дать вам несколько советов о том, как лучше писать код: ') – gntskn

ответ

34

Все ваши функции выполняются при создании словаря, а не при доступе к ключу.

Вы должны использовать lambda (без каких-либо параметров, они уже известны), чтобы убедиться, что функция вызывается только тогда, когда требуется:

switcher = { 
    0: lambda : vertical.Vertical_Tank(level, area), 
    1: lambda : horiz.Horiz_Cylinder_Dished_Ends(dish, radius, level, length), 
    2: lambda : strapping.Calc_Strapped_Volume(Strapping_Table, level), 
    3: lambda : poly.Fifth_Poly_Calcs(Tank_Number) 
} 

затем вызвать, когда вы вернетесь, с сообщением об ошибке, как лямбда что возвращает его:

return switcher.get(Tank_Shape, lambda : "ERROR: Tank type not valid")() 
+8

или _functools.partial_ вместо lambda – volcano

+0

не знал о 'functools.partial'. Верно подмечено. (Я надеюсь повторно использовать его в будущем ответе :)) Однако в этом случае «лямбда» представляется лучшим выбором, поскольку все аргументы передаются не только некоторым. –

+2

Всегда рад быть полезным :-), _partial_ отлично подходит для обратных вызовов. Я сам грешу с _lambda_ достаточно часто, но - ИМХО, в этом случае _partial_ выглядит немного чище. Вопрос вкуса. – volcano

7

Что вы делаете в своем коде, это создание словаря с целыми ключами (0-3) и результатов функции в качестве значений. Следовательно, вы сначала вызываете все функции, а затем получаете доступ к возвращаемым значениям этих функций. Я бы поменял ваш код следующим образом:

def Tank_Shape_Calcs(Tank_Shape, level, area, dish, radius, length, Strapping_Table, Tank_Number): 
    switcher = { 
     0: (vertical.Vertical_Tank, (level, area)), 
     1: (horiz.Horiz_Cylinder_Dished_Ends, (dish, radius, level, length)), 
     2: (strapping.Calc_Strapped_Volume, (Strapping_Table, level)), 
     3: (poly.Fifth_Poly_Calcs, (Tank_Number,)) 
    } 
    func, args = switcher.get(Tank_Shape, (None, None)) 
    if func is not None: 
     return func(*args) 

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

+0

Это хорошая идея. Однако вы не эмулировали сообщение об ошибке, поэтому, если 'Tank_Shape'>> 3, он падает, а не возвращает ясную строку ошибки. –

+0

Да, вы правы, я вставил чек – BloodyD

+1

Для меня это похоже на самое элегантное решение, предлагаемое до сих пор. – SethMMorton

17

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

  • Переосмысление switcher при каждом вызове функции Tank_Shape_Calcs, это вообще не является хорошей идеей.
  • Требуя все аргументы, которые передаются (из-за их определения как positionals), когда лишь немногие из них могут быть необходимы, поэтому у нас есть *args :-)

Если мое понимание того, что вы «повторно до правильна, я бы переместить переключатель вне функции, как и Tank_Shape к function объекта отображения в:

switcher = { 
    0: vertical.Vertical_Tank, 
    1: horiz.Horiz_Cylinder_Dished_Ends, 
    2: strapping.Calc_Strapped_Volume, 
    3: poly.Fifth_Poly_Calcs 
} 

Затем определяют Tank_Shape_Calcs взять лишние аргументы в виде кортежа с *args:

def Tank_Shape_Calcs(Tank_Shape, *args): 
    return switcher.get(Tank_Shape, lambda *_: "ERROR: Tank type not valid")(*args) 

и вызывать вашу функцию после .get тин его.

Это также играет от уловку Джин, чтобы определить lambda в .get, но делает это с *_ для того, чтобы позволить ему дозвонились со многими аргументами (которые, следовательно, игнорируются).

+2

просто красивый! –

+1

@ Jean-FrançoisFabre Я все еще смотрю на него, опасаясь, что я что-то пропустил, тот факт, что минимальный пример, который я могу проверить, не подает, - это кормить мою неуверенность. –

+0

Я понимаю. По крайней мере, лямбда-вещь - достаточно безопасная модификация. Пусть OP проверит ваше решение. Если это не сработает, я выведу свои 4 upvotes :) –

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