С модулем operator
все довольно просто. Вот пример:
>>> import operator
>>> bucket = (operator.ge, -100, operator.le, -5)
>>> def in_bucket(value, bucket): return bucket[0](value, bucket[1]) and bucket[2](value, bucket[3])
...
>>> in_bucket(-101, bucket)
False
>>> in_bucket(-100, bucket)
True
>>> in_bucket(-5, bucket)
True
>>> in_bucket(-4, bucket)
False
Но вы можете добиться большего успеха, определив более общую структуру:
>>> conditions = ((operator.ge, -100), (operator.le, -5))
>>> def match_conditions(value, conditions): return all(c[0](value, c[1]) for c in conditions)
...
>>> match_conditions(-101, conditions)
False
>>> match_conditions(-100, conditions)
True
>>> match_conditions(-5, conditions)
True
>>> match_conditions(-4, conditions)
False
Оператор all
возвращает true, если все условия выполнены. Основное различие между bucket
и conditions
заключается в том, что вы можете добавить условия, которые не касаются границ, например, значение должно быть парным:
>>> conditions = ((operator.ge, -100), (operator.le, -5), (lambda v, _: v%2==0, None))
>>> match_conditions(-7, conditions)
False
>>> match_conditions(-6, conditions)
True
>>> match_conditions(-5, conditions)
False
Теперь вы можете использовать словарь для обобщения ваших условий (первый пример, который вы привели):
>>> value_by_conditions = {
... ((operator.lt, -100),): -15,
... ((operator.ge, -100), (operator.le, -5)): -4,
... ((operator.gt, -5), (operator.le, 5)): 18,
... ((operator.gt, 5),): 88,
... }
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(23, cs)), None)
88
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(-101, cs)), None)
-15
>>> next((v for cs, v in value_by_conditions.items() if match_conditions(-100, cs)), None)
-4
Примечания:
- Я использовал кортежи, поскольку списки не могут быть хешируемыми (и поэтому не могут использоваться в качестве ключей dict);
next((x for x in xs if <test>), None)
принимает первый элемент в xs
, который проходит тест. Если ни один элемент не проходит тест, возвращается значение по умолчанию None
;
- В более старых версиях Python (<3.7) у вас нет гарантии порядка тестов. Это важно, если у вас есть перекрывающиеся условия. </li>
- Это явно неоптимально, потому что вы проверяете, если
value < 100
, тогда если value >= 100
и т. Д.
Это действительно питон? Я не уверен. Взгляните на https://www.python.org/dev/peps/pep-0020/, чтобы составить свою идею.