sla*_*lum 18 python range slice python-3.x
我正在使用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
Run Code Online (Sandbox Code Playgroud)
嗯,这个问题很明显 - 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
Run Code Online (Sandbox Code Playgroud)
但对我来说不明显的是解决方案.我怎么称呼range所以它会在每种情况下都有效?我正在寻找一种不错的pythonic方法来做到这一点.
谢谢 :)
Cra*_*sta 10
有一种更简单的方法(至少在3.4中,我目前没有3.3,而且我没有在更改日志中看到它).
假设你的类已经有一个已知的长度,你可以只切片那个大小的范围:
>>> range(10)[1:5:2]
range(1, 5, 2)
>>> list(range(10)[1:5:2])
[1, 3]
Run Code Online (Sandbox Code Playgroud)
如果您不知道先验的长度,您将不得不这样做:
>>> class A:
def __getitem__(self, item):
if isinstance(item, slice):
return list(range(item.stop)[item])
>>> a = A()
>>> a[1:5:2]
[1, 3]
>>> a[1:5]
[1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
尝试
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
Run Code Online (Sandbox Code Playgroud)
这将重新解释.start,.step如果它们是适当的None.
另一种选择可以是.indices()切片的方法.使用条目数调用它并将其重新解释None为适当的值,并在给定的length参数周围包含负值:
>>> 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)
Run Code Online (Sandbox Code Playgroud)
这取决于你打算用负指数做什么......
小智 6
切片包括start,stop,和step参数,并且可以与任一被创建切片表示法或使用slice 内置的.任何(或全部)的start,stop和step参数可以None.
# valid
sliceable[None:None:None]
# also valid
cut = slice(None, None, None)
sliceable[cut]
Run Code Online (Sandbox Code Playgroud)
但是,正如原始问题所指出的,该range函数不接受None参数.你可以通过各种方式解决这个问题......
if item.start None:
return list(range(item.start, item.stop))
return list(range(item.start, item.stop, item.step))
Run Code Online (Sandbox Code Playgroud)
......由于任何或所有参数可能会变得不必要地复杂化None.
start = item.start if item.start is None else 0
step = item.step if item.step is None else 1
return list(range(item.start, item.stop, item.step))
Run Code Online (Sandbox Code Playgroud)
......这是明确的,但有点冗长.
return list(range(item.start if item.start else 0, item.stop, item.step if item.step else 1))
Run Code Online (Sandbox Code Playgroud)
......这也是不必要的冗长.
ifnone = lambda a, b: b if a is None else a
range(ifnone(item.start, 0), item.stop, ifnone(item.step, 1)
Run Code Online (Sandbox Code Playgroud)
......这很难理解.
return list(range(item.start or 0, item.stop or len(self), item.step or 1))
Run Code Online (Sandbox Code Playgroud)
我发现使用or最简单的分配合理的默认值.它明确,简单,清晰,简洁.
为了完成你也应该处理整数索引(实施int,long通过检查等)isinstance(item, numbers.Integral)(见INT VS numbers.Integral).
定义__len__以允许使用len(self)默认停止值.
最后提出适用TypeError于无效索引(例如字符串等).
class A:
def __len__(self):
return 0
def __getitem__(self, item):
if isinstance(item, numbers.Integral): # item is an integer
return item
if isinstance(item, slice): # item is a slice
return list(range(item.start or 0, item.stop or len(self), item.step or 1))
else: # invalid index type
raise TypeError('{cls} indices must be integers or slices, not {idx}'.format(
cls=type(self).__name__,
idx=type(item).__name__,
))
Run Code Online (Sandbox Code Playgroud)
这里的所有其他答案都完全遗漏了它。
在一般情况下,您根本无法将 a 转换slice为 a 。range
没有足够的信息。您需要知道要尝试切片的列表(或其他序列类型)的长度。
一旦你有了这个,你就可以在 Python 3 中使用slice.indices()轻松创建一个范围
按照您提供的示例:
class A:
def __init__(self, mylist):
self.mylist = mylist
def __getitem__(self, item):
if isinstance(item, slice):
mylen = len(self.mylist)
return list(range(*item.indices(mylen)))
mylist = [1, 2, 'abc', 'def', 3, 4, None, -1]
a = A(mylist)
a[1:5] # produces [1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6810 次 |
| 最近记录: |