Я работаю в области, в которой диапазоны обычно описываются включительно. У меня есть понятные человеку описания, такие как from A to B, которые представляют диапазоны, которые включают обе конечные точки - например, from 2 to 4 означает 2, 3, 4.
Каков наилучший способ работы с этими диапазонами в коде Python? Следующий код работает для генерации инклюзивных диапазонов целых чисел, но мне также необходимо выполнить инклюзивные операции срезов:
def inclusive_range(start, stop, step):
return range(start, (stop + 1) if step >= 0 else (stop - 1), step)
Единственное полное решение, которое я вижу, - это явное использование + 1 (или - 1) каждый раз, когда я использую range или обозначение среза (например, range(A, B + 1), l[A:B+1], range(B, A - 1, -1)). Это повторение действительно лучший способ работать с инклюзивными диапазонами?
Изменить: Спасибо L3viathan за ответ. Написание функции inclusive_slice для дополнения inclusive_range, безусловно, вариант, хотя я, вероятно, написал бы ее следующим образом:
def inclusive_slice(start, stop, step):
...
return slice(start, (stop + 1) if step >= 0 else (stop - 1), step)
... здесь представляет код для обработки отрицательных индексов, которые непросты при использовании со слайсами - обратите внимание, например, что функция L3viathan дает неверные результаты, если slice_to == -1.
Однако кажется, что использовать функцию inclusive_slice было бы неудобно - действительно ли l[inclusive_slice(A, B)] лучше, чем l[A:B+1]?
Есть ли лучший способ обработки инклюзивных диапазонов?
Изменить 2: Спасибо за новые ответы. Я согласен с Фрэнсисом и Корли, что изменение значения операций срезов, глобально или для определенных классов, приведет к значительной путанице. Поэтому я сейчас склоняюсь к написанию функции inclusive_slice.
Чтобы ответить на мой собственный вопрос из предыдущего редактирования, я пришел к выводу, что использование такой функции (например, l[inclusive_slice(A, B)]) было бы лучше, чем ручное добавление/вычитание 1 (например, l[A:B+1]), поскольку это позволило бы получить крайние случаи ( такие как B == -1 и B == None) для обработки в одном месте. Можем ли мы уменьшить неловкость при использовании функции?
Изменить 3: Я думал о том, как улучшить синтаксис использования, который в настоящее время выглядит как l[inclusive_slice(1, 5, 2)]. В частности, было бы хорошо, если бы создание включающего слайса напоминало стандартный синтаксис слайса. Для этого вместо inclusive_slice(start, stop, step) может быть функция inclusive, которая принимает срез в качестве параметра. Идеальным синтаксисом использования для inclusive была бы строка 1:
l[inclusive(1:5:2)] # 1
l[inclusive(slice(1, 5, 2))] # 2
l[inclusive(s_[1:5:2])] # 3
l[inclusive[1:5:2]] # 4
l[1:inclusive(5):2] # 5
К сожалению, это не разрешено Python, который позволяет использовать только синтаксис : в []. Поэтому inclusive должен вызываться с использованием синтаксиса 2 или 3 (где s_ действует как версия, предоставленная numpy).
Другие возможности состоят в том, чтобы превратить inclusive в объект с __getitem__, разрешающим синтаксис 4, или применить inclusive только к параметру stop слайса, как в синтаксисе 5. К сожалению, я не верю, что последнее можно заставить работать, поскольку inclusive требует знания значения step.
Из возможных синтаксисов (оригинал l[inclusive_slice(1, 5, 2)], плюс 2, 3 и 4), какой из них лучше всего использовать? Или есть другой, лучший вариант?
Окончательное редактирование: Спасибо всем за ответы и комментарии, это было очень интересно. Я всегда был поклонником философии Python "один способ сделать это", но эта проблема была вызвана конфликтом между Python "один путь" и "один путь", запрещенным проблемной областью. Я определенно оценил TIMTOWTDI в языковом дизайне.
За то, что дал первый и получивший наибольшее количество голосов ответ, я присуждаю награду L3viathan.