Подтвердить что ты не робот

Как сопоставить ряд условий как ключей в словаре?

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

def printMessage(mystring):
    # Switch statement without a dictionary
    if mystring == "helloworld":
        print "say hello"
    elif mystring == "byeworld":
        print "say bye"
    elif mystring == "goodafternoonworld":
        print "good afternoon"


def printMessage(mystring):
    # Dictionary equivalent of a switch statement
    myDictionary = {"helloworld": "say hello",
                    "byeworld": "say bye",
                    "goodafternoonworld": "good afternoon"}
    print myDictionary[mystring]

Однако, если используются условия, отличные от равенства (==), которые возвращают true из false, они не могут быть отображены так легко:.

if i > 0.5:
    print "greater than 0.5"
elif i == 5:
    print "it is equal to 5"
elif i > 5 and i < 6:
    print "somewhere between 5 and 6"

Вышеуказанное не может быть напрямую преобразовано в пару слов-словаря слова:

# this does not work
mydictionary  = { i > 0.5: "greater than 0.5" }

Лямбда может использоваться, поскольку она хешируется, но единственный способ получить полученную строку из карты - передать тот же лямбда-объект в словарь, а не когда оценка лямбда истинна: ​​

x = lambda i: i > 0.5
mydictionary[x] = "greater than 0.5"
# you can get the string by doing this:
mydictionary[x]
# which doesnt result in the evaluation of x

# however a lambda is a hashable item in a dictionary
mydictionary = {lambda i: i > 0.5: "greater than 0.5"}

Кто-нибудь знает о методе или методе создания сопоставления между оценкой лямбда и возвращаемым значением? (это может быть похоже на сопоставление шаблонов в функциональном языке)

4b9b3361

Ответ 1

Ваши условия носят последовательный характер; вы хотите протестировать один за другим, а не отображать небольшое количество ключей на значение здесь. Изменение порядка условий может изменить исход; значение 5 приводит к "greater than 0.5" в вашем примере, а не "it is equal to 5".

Используйте список кортежей:

myconditions  = [
    (lambda i: i > 0.5, "greater than 0.5"),
    (lambda i: i == 5, "it is equal to 5"),
    (lambda i: i > 5 and i < 6, "somewhere between 5 and 6"),
]

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

for test, message in myconditions:
    if test(i):
        return message

Повторный заказ тестов изменит результат.

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

Ответ 2

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

from collections import namedtuple

Case = namedtuple('Case', ['condition', 'code'])

cases = (Case('i > 0.5',
            """print 'greater than 0.5'"""),

         Case('i == 5',
            """print 'it is equal to 5'"""),

         Case('i > 5 and i < 6',
            """print 'somewhere between 5 and 6'"""))

def switch(cases, **namespace):
    for case in cases:
        if eval(case.condition, namespace):
            exec(case.code, namespace)
            break
    else:
        print 'default case'

switch(cases, i=5)

Вывод:

greater than 0.5

Ответ 3

Не имеет прямого отношения, но я часто использую парадигму, подобную приведенному ниже примеру, для замены каскадного ifs на поиск в dictionaruy.

def multipleifs(a=None,b=None,c=None,d=None,e=None):
    """ Func1 with cascaded if
    >>> multipleifs(10,20,30,40,50)
    160
    """

    x=10
    if a:
        x += 10
    if b:
        x += 20
    if c:
        x += 30
    if d:
        x += 40
    if e:
        x += 50

    return x

def dictif(a=None,b=None,c=None,d=None,e=None):
    """ Func2 with dictionary replacing multiple ifs
    >>> dictif(10,20,30,40,50)
    160
    """

    x, mydict = 10, dict(enumerate([10,20,30,40,50]))

    for count, item in enumerate([a,b,c,d,e]):
        if item: x += mydict.get(count,0)

    return x