将切片转换为范围

2022-03-26 00:00:00 python python-3.x slice range

问题描述

我使用的是Python3.3。我要获取slice对象并使用它创建新的range对象。

大概是这样的:

>>> class A:
    def __getitem__(self, item):
        if isinstance(item, slice):
            return list(range(item.start, item.stop, item.step))

>>> a = A()
>>> a[1:5:2] # works fine
[1, 3]
>>> a[1:5] # won't work :(
Traceback (most recent call last):
  File "<pyshell#18>", line 1, in <module>
    a[1:5] # won't work :(
  File "<pyshell#9>", line 4, in __getitem__
    return list(range(item.start, item.stop, item.step))
TypeError: 'NoneType' object cannot be interpreted as an integer

嗯,问题在这里很明显-range不接受None作为值:

>>> range(1, 5, None)
Traceback (most recent call last):
  File "<pyshell#19>", line 1, in <module>
    range(1, 5, None)
TypeError: 'NoneType' object cannot be interpreted as an integer

但(对我而言)不明显的是解决方案。我如何调用range以便它在所有情况下都能工作? 我正在寻找一种很好的蟒蛇方式来做这件事。


解决方案

尝试

class A:
    def __getitem__(self, item):
        ifnone = lambda a, b: b if a is None else a
        if isinstance(item, slice):
            if item.stop is None:
                # do something with itertools.count()
            else:
                return list(range(ifnone(item.start, 0), item.stop, ifnone(item.step, 1)))
        else:
            return item

这将重新解释.start.step(如果它们是None)。


另一个选项可以是切片的.indices()方法。它使用条目数调用,并将None重新解释为适当的值,并将负值括在给定的长度参数周围:

>>> a=slice(None, None, None)
>>> a.indices(1)
(0, 1, 1)
>>> a.indices(10)
(0, 10, 1)
>>> a=slice(None, -5, None)
>>> a.indices(100)
(0, 95, 1)

这取决于您打算如何处理负指数.

相关文章