User:Xyy23330121/Python/类的方法与Python的计算/对索引为slice对象的支持

来自维基学院

本页面将讨论对索引为 slice 对象时,应如何设计 __getitem__ 方法。并最终给出一个简单的实现。

当然,如果读者想要不按照常规、让 __getitem__ 根据输入的 slice 随意输出一个结果。当然也是可以的。

创建 slice 对象[编辑 | 编辑源代码]

slice 对象可以由slice(start, stop, step=None)slice(stop)[1]的方式给出。我们可以用以下方式确认:传入“索引”参数的确实是 slice 对象。

class getSlice:
    def __getitem__(self, key):
        return key

get = getSlice()
print(obj[0:5:2])                 #输出:slice(0, 5, 2)
print(obj[0:5:2] == slice(0,5,2)) #输出:True

与用作索引时不同,用 slice 函数创建 slice 对象时一定要传入 stop 参数。

支持 slice 作为索引的要点[编辑 | 编辑源代码]

slice 对象的属性[编辑 | 编辑源代码]

slice 对象具有三个只读属性 startstopstep。这三个属性,对于索引的实现很有帮助。如以下示例:

class getSlice:
    def __getitem__(self, key): return key

a = get[:]
b = get[0:]
c = get[0:5:1]
print(a.start,a.stop,a.step) #输出:None None None
print(b.start,b.stop,b.step) #输出:0 None None
print(c.start,c.stop,c.step) #输出:0 5 1

可以看出,在使用索引时,如果不输入对应位置的内容,则会直接传入 None。在进行 slice 对象支持时,一定要注意对 None 的处理。

slice 作索引时的特点[编辑 | 编辑源代码]

slice 索引用作列表、元组和字符串时,总是返回子列表、子元组和子字符串。

slice 索引在 start 或 end 超出整数索引范围时也能使用。

slice 索引在 start >= end and step > 0 时返回空的容器;在 start <= end and step < 0 时也返回空的容器。

通用的简单实现[编辑 | 编辑源代码]

如果不希望考虑那么多内容,读者也可以简单一点。注意到以下代码可以直接输出所需的对应索引序列:

(i for i in range(len(self)))[key]

我们可以先支持用可迭代序列作索引,再把slice,用 Python 已有的方法直接转换为可迭代序列。

from collections.abc import Iterator

class MyClass:
    ...
    def __getitem__(self, key):
        #对可迭代序列作索引的支持
        if isinstance(key, Iterator):
            return MyClass([self[i] for i in key])
        #直接把 slice 用(0,1,...)[slice]的方式转化为可迭代序列。
        if isinstance(key, slice):
            return self[(i for i in range(len(self)))[key]]
        ...
        raise ValueError("不被支持的索引类型。")
    def __len__(self):
        ...

延申[编辑 | 编辑源代码]

具体来讲,可以把 : 当成“只有在索引的方括号中才可用的运算符”。该运算符结合其左右的内容,生成 slice 对象。我们看以下例子:

class getSlice:
    def __getitem__(self, key): return key

get = getSlice()
print(get[:,:])  #(slice(None, None, None), slice(None, None, None))

可以看出,该运算符的优先级高于“生成 tuple 对象”的逗号运算符。

參考文獻[编辑 | 编辑源代码]