2013-07-04 3 views
1

Я пытаюсь найти чистый способ обработки различных взаимоисключающих входов функций. Идея состоит в том, что у меня есть функция, которая возвращает 4 значения (эти значения связаны через математические уравнения), и когда вы вводите одно из 4 значений, оно возвращает все значения.Какой самый Pythonic способ обработки разных взаимоисключающих функций?

В настоящее время функция работает следующим образом:

#example relations are simply: b=1+a, c=0.5*a, d=sqrt(a) 
def relations(v, vtype="a"): 
    if vtype=="a": 
     a = v 
    elif vtype=="b": 
     a = v - 1 
    elif vtype=="c": 
     a = 2 * v 
    elif vtype=="d": 
     a = v ** 2 

    b = 1 + a 
    c = 0.5 * a 
    d = a ** 0.5 

    return a,b,c,d 

Пользователь указывает, что входной переменной с помощью строки VType, и он возвращает все значения. Пользователь не может вводить несколько разных входных значений (будет избыточным, поскольку все неизвестные могут быть определены из одного входного значения).

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

Заранее благодарен!

+1

Какая часть вашей текущей реализации чувствует себя грязным? –

+1

После ввода пользователем типа ввода в виде строки через переменную vtype. Я имею в виду, давай .... – Wilco

+0

Это более pythonic, чем любой из ответов до сих пор. Единственное, что беспокоит, - это магические константы '' a'', ''b'' и т. Д. – bereal

ответ

2

Общий подход избежать многих if - elif в том, чтобы построить словарь функций:

def relations(v, vtype='a'): 
    functions = { 
     'a': lambda x: x, 'b': lambda x: x-1, 
     'c': lambda x: x * 2, 'd': lambda x: x**2 
    } 

    a = functions[vtype](v) 
    b = 1 + a 
    c = 0.5 * a 
    d = a ** 0.5 
    return a,b,c,d 

Если эта функция не является узким местом вы можете избежать использования lambda с и просто сделать:

values = {'a': v, 'b': v-1, 'c': v * 2, 'd': v**2} 
a = values[vtype] 

Если вам не нравится идея иметь vtype в подписи функции вы можете использовать один **kwargs аргумент:

def relations(**kwargs): 
    if len(kwargs) != 1 or not set('abcd').intersection(kwargs): 
     raise ValueError('Invalid parameters') 
    vtype, v = kwargs.popitem() 
    functions = { 
     'a': lambda x: x, 'b': lambda x: x-1, 
     'c': lambda x: x * 2, 'd': lambda x: x**2 
    } 

    a = functions[vtype](v) 
    b = 1 + a 
    c = 0.5 * a 
    d = a ** 0.5 
    return a,b,c,d 

Тогда называют его:

relations(a=...) 
relations(b=...) 
+0

Большое спасибо за этот ответ! Я должен был прояснить исходный пост, заявив, что мне не нравится аргумент vtype. Я согласен, что подходящее решение - это kwargs. Лямбда не будет работать, потому что для некоторых значений мне нужно выполнить сложное математическое уравнение, чтобы инвертировать отношения (или даже итерацию через newton-raphson), поэтому структура if-elif не является проблемой. Еще раз спасибо! – Wilco

0

Вы могли бы использовать что-то вроде этого:

def relations(a=None, b=None, c=None, d=None): 
    if a is not None: 
     pass 
    elif b is not None: 
     a = b - 1 
    elif c is not None: 
     a = 2 * c 
    elif d is not None: 
     a = d ** 2 
    else: 
     raise TypeError('At least one argument needed') 

    # your calculations 

Затем вы можете использовать функцию просто, например, с relations(c=10) или relations(a=2). Так что вам не нужен аргумент vtype.

Первый переданный аргумент используется для расчета a. Если вы вызовете функцию с более чем одним аргументом, будет использоваться только первый, а остальные будут игнорироваться (например, relations(b=2, c=5) будет использоваться только b, а c игнорируется).

+1

Не используйте'! = 'С' None'. Используйте 'is not':', если a не None: '. – Bakuriu

2

Вы можете использовать различные ключевые аргументы:

def relations(**kwargs): 
    if 'a' in kwargs: 
     a = kwargs['a'] 
    elif 'b' in kwargs: 
     a = kwargs['b'] - 1 
    elif 'c' in kwargs: 
     a = kwargs['c'] * 2 
    elif 'd' in kwargs: 
     a = kwargs['d'] ** 2 
    else: 
     raise TypeError('missing an argument') 

    b = 1 + a 
    c = 0.5 * a 
    d = a ** 0.5 

    return a, b, c, d 

Затем используйте с именованными параметрами:

relations(a=2) 
relations(b=4) 
relations(c=9) 
relations(d=0) 
1

Вы можете определить свои vtypes как функции, и передать функцию в качестве параметра

def a(v): 
    return v 

def b(v): 
    return v-1 

def c(v): 
    return 2*v 

def d(v): 
    return v**2 

def relations(v, vtype=a): 
    value_a = vtype(v) 
    value_b = 1 + value_a 
    value_c = 0.5 * value_a 
    value_d = value_a ** 0.5 
    return value_a,value_b,value_c,value_d 

С этим вы можете избавиться от if/elif тоже.

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