25

我做了一个如下的课程:

class MyList(list):
    def __init__(self, lst):
        self.list = lst

我希望在 MyList 中覆盖切片功能

4

3 回答 3

46

您需要提供 custom和__getitem__()hooks 。__setitem____delitem__

这些在对列表进行切片时传递一个切片对象;这些具有start,stopstep属性。但是,这些值可以是None, 以表示默认值。考虑到当您使用负步幅时默认值实际上会发生变化!

但是,它们也有一个slice.indices()方法,当给定一个长度时,它会产生一个(start, stop, step)适合range()对象的值的元组。此方法处理诸如以负步幅进行切片且没有开始或停止索引等令人讨厌的细节:

def __getitem__(self, key):
    if isinstance(key, slice):
        indices = range(*key.indices(len(self.list)))
        return [self.list[i] for i in indices]
    return self.list[key]

或者,对于您的情况:

def __getitem__(self, key):
    return self.list[key]

因为 alist可以直接取slice对象。

在 Python 2 中,list.__getslice__如果实现了没有跨步的切片(因此只有开始和停止索引),则调用它,并且内置list类型实现了它,因此您也必须覆盖它;对您的方法的简单委托__getitem__应该可以:

def __getslice__(self, i, j):
    return self.__getitem__(slice(i, j))
于 2013-04-16T09:13:28.990 回答
7
class MyList(list):
    def __init__(self, lst):
        self.list = lst

没有多大意义......self是列表对象本身,并且此时它已经创建,也许您想要覆盖__new__,但是您可能不需要触摸它。无论如何,您想像这样覆盖__getitem__

def __getitem__(self, val):
    if isinstance( val, slice):
        # do stuff here
于 2013-04-16T09:13:50.663 回答
0

正如@Martijn Pieters@jamylak所说,您需要实现该__getitem__方法。

一般来说,如果一个人想要覆盖它的超类的切片功能,并继续使用已经使用超类的超类方法__getitem__,只需将其拆分为案例,并从两个世界中受益。

例如:

import pandas as pd

class SubFrame(pd.DataFrame):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def __getitem__(self, item):
        if isinstance(item, slice):
            # your implementation
            print("'My slicing'")
            return SubFrame(super().__getitem__(item))
        else:
            return super().__getitem__(item)

现在你可以这样做:

>>> sf = SubFrame({'A': (10,20,30,40,50)})
>>> sf[1:-2]
'My slicing'
    A
1  20
2  30
>>> type(sf[1:-2])
<class '__main__.SubFrame'>

并且[]仍然会打电话给超级的__getitem__

>>> sf['A']  # super's __getitem__
0    10
1    20
2    30
3    40
4    50
Name: A, dtype: int64
>>> type(sf['A'])
<class 'pandas.core.series.Series'>
于 2021-10-04T19:42:11.703 回答