解析python列表索引操作、切片操作的原理

列表元素的获取可以使用索引或者切片,这个时候调用的是__getitem__方法

a[i] # 这是一个简单的数字索引,使用即元素“位置”获取元素值
a[i:j];a[i:j:k] # 这是切片操作,i为起始位置,j为结束位置,k为步进值

当使用赋值表达式对元素进行赋值时,调用的时__setitem__方法

a[0]=10
#也可以使用这样的方法替换多个元素
a[0:2]=[11,12]

当使用del语句删除一个值时,调用的是__delitem__方法

del a[0]
del a[0,2]

当使用类似于a[:],a[1:2],a[1,10,2]这样的操作时,实际上是在写slice表达式。slice表达式必须要有三个参数,即起始,结束和步进。之所以我们可以少写参数,是因为内部使用了 indices 这个方法对参数进行了补全。

class Explore(list):
    def __getitem__(self, item):
        print(item,item.indices(len(self)))
        return super().__getitem__(item)
>> a = Explore('1234')
>> a[:]
>> slice(None, None, None) (0, 4, 1) # 虽然我们传入的表达式仅为一个:,但是indices进行了补全
   ['1', '2', '3', '4']

当我们要使用继承的方式实现自己的list,并且对其中的方法和操作进行自己的一些定义,那么一定不要忘记slice。下面是一个支持平均数和标准差方法的list。

class StatsList(list):
    def __init__(self, *args, **kwargs):
        self.sum0 = 0  # 列表中元素的个数,len(self)
        self.sum1 = 0  # 列表中所有元素的和, sum(self)
        self.sum2 = 0  # 列表中所有元素的平方和, sum(x**2 for x in self)
        super().__init__(*args, **kwargs)
        for x in self:
            self._new(x)

    # 当添入元素时调用
    def _new(self, value):
        self.sum0 += 1
        self.sum1 += value
        self.sum2 += value * value

    # 当移除元素时调用
    def _rmv(self, value):
        self.sum0 -= 1
        self.sum1 -= value
        self.sum2 -= value * value

    def insert(self, index, value):
        super().insert(index, value)
        self._new(value)

    def pop(self, index=-1):
        value = super().pop(index)
        self._rmv(value)

    def __setitem__(self, key, value):
        # 如果key是slice实例,那么在进行切片赋值
        if isinstance(key, slice):
            start, stop, step = key.indices(self.sum0)
            for i in range(start, stop, step):
            	self._rmv(self[i])
            super().__setitem__(key, value)
            # 这里value不存在不可迭代的情况,因为 slice 操作参数必须为可迭代对象
            for x in value:
                self._new(x)
        else:
            self._rmv(self[key])
            self._new(value)
            super().__setitem__(key, value)

    def __delitem__(self, key):
        if isinstance(key, slice):
            start, stop, step = key.indices(self.sum0)
            for i in range(start, stop, step):
            	self._rmv(self[i])
            super().__delitem__(key)
        else:
            self._rmv(self[key])
            super().__delitem__(key)

    """
    其他影响计算的函数有: extend, __iadd__, remove, append, 
    """

    # 平均数
    @property
    def mean(self):
        return self.sum1 / self.sum0

    # 标准差
    @property
    def stdev(self):
        return math.sqrt(self.sum0 * self.sum2 - self.sum1 ** 2) / self.sum0
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值