use*_*783 43 python range slice
我在一个领域工作,其中范围通常包含在内.我有人类可读的描述,例如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:谢谢你的新答案.我同意Francis和Corley的观点,即无论是在全球范围内还是在某些类别中,改变切片操作的含义都会导致严重的混淆.因此,我现在倾向于编写一个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是line 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.
L3v*_*han 14
为包含切片编写一个附加函数,并使用它而不是切片.虽然有可能例如子类列表并实现__getitem__对切片对象的反应,但我建议反对它,因为你的代码的行为与除了你之外的任何人的期望相反 - 也可能在一年之内.
inclusive_slice 可能看起来像这样:
def inclusive_slice(myList, slice_from=None, slice_to=None, step=1):
    if slice_to is not None:
        slice_to += 1 if step > 0 else -1
    if slice_to == 0:
        slice_to = None
    return myList[slice_from:slice_to:step]
我个人会做的,就是使用你提到的"完整"解决方案(range(A, B + 1),l[A:B+1])并做好评论.
因为在Python中,结束索引总是独占的,所以值得考虑在内部始终使用"Python-convention"值.这样,您就可以避免在代码中混淆两者.
只有通过专用转换子程序处理"外部表示":
def text2range(text):
    m = re.match(r"from (\d+) to (\d+)",text)
    start,end = int(m.groups(1)),int(m.groups(2))+1
def range2text(start,end):
    print "from %d to %d"%(start,end-1)
或者,您可以使用真正的匈牙利表示法标记包含"异常"表示的变量.
如果您不想指定步长而是指定步数,可以使用numpy.linspace包含起点和终点的选项
import numpy as np
np.linspace(0,5,4)
# array([ 0.        ,  1.66666667,  3.33333333,  5.        ])
与其创建非传统的 API 或扩展数据类型(如 )list,不如在内置函数上创建一个包装器,slice以便您可以将其传递到任何可能进行切片的地方。
例如,包含切片看起来像
def inclusive_slice(start, stop=None, step=None):
    if stop is not None:
        stop += 1
    if stop == 0:
        stop = None
    return slice(start, stop, step)
您可以将它用于任何序列类型。
>>> range(1, 10)[inclusive_slice(1, 5)]
[2, 3, 4, 5, 6]
>>> "Hello World"[inclusive_slice(0, 5, 2)]
'Hlo'
>>> (3, 1, 4, 1, 5, 9, 2, 6)[inclusive_slice(1, -2)]
(1, 4, 1, 5, 9, 2)
最后,您还可以创建一个名为的包含范围inclusive_range来补充包含切片:
def inclusive_range(start, stop, step):
    return range(start, (stop + 1) if step >= 0 else (stop - 1), step)