如何定义getitem类以处理普通索引和切片?
当您在下标符号中使用冒号时,会自动创建Slice对象,并将其传递给 __getitem__
。使用 isinstance
检查是否存在Slice对象:
from __future__ import print_function
class Sliceable(object):
def __getitem__(self, subscript):
if isinstance(subscript, slice):
print(subscript.start, subscript.stop, subscript.step)
else:
print(subscript)
假设我们正在使用一个range对象,但我们想要切片返回列表而不是新的range对象(就像它现在所做的那样):
>>> range(1,100, 4)[::-1]
range(97, -3, -4)
由于内部限制,我们无法对范围进行子类化,但是我们可以将其委托:
class Range:
"""like builtin range, but when sliced gives a list"""
__slots__ = "_range"
def __init__(self, *args):
self._range = range(*args)
def __getattr__(self, name):
return getattr(self._range, name)
def __getitem__(self, subscript):
result = self._range.__getitem__(subscript)
if isinstance(subscript, slice):
return list(result)
else:
return result
r = Range(100)
我们没有完全可替代的Range对象,但它相当接近:
>>> r[1:3]
[1, 2]
>>> r[1]
1
>>> 2 in r
True
>>> r.count(3)
1
为了更好地理解切片符号,这里是Sliceable的示例用法:
>>> sliceme = Sliceable()
>>> sliceme[1]
1
>>> sliceme[2]
2
>>> sliceme[:]
None None None
>>> sliceme[1:]
1 None None
>>> sliceme[1:2]
1 2 None
>>> sliceme[1:2:3]
1 2 3
>>> sliceme[:2:3]
None 2 3
>>> sliceme[::3]
None None 3
>>> sliceme[::]
None None None
>>> sliceme[:]
None None None
Python 2注意:
在Python 2中,有一个已经不再推荐使用的方法,当子类化某些内置类型时可能需要覆盖它。
根据 datamodel文档:
object.__getslice__(self, i, j)
自2.0版本起不推荐使用: 将切片对象作为参数传递给__getitem__()
方法。(然而,CPython中的内置类型仍然实现__getslice__()
。因此,在实现切片时必须在派生类中覆盖它。)
这在Python 3中已经不存在了。
__getslice__
。请参阅https://docs.python.org/2/reference/datamodel.html#object.__getslice__。 - gregorySalvan__get/set/delslice__
。虽然这很微妙。 - user2357112__getitem__
可以接收一个slice
,但也可以像c[0]
一样接收一个int
。请参阅https://docs.python.org/3/reference/datamodel.html#object.__getitem__。 - Luca