python实现可切片的对象

Python 切片的基本语法

Python 切片的基本语法为 [start:stop:step],使用切片会返回一个新列表,其中:

  • start 是切片的起始索引(包含该索引)。
  • stop 是切片的结束索引(不包含该索引)。
  • step 是切片的步长,默认为 1。

切片的使用示例

# 定义一个列表
my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 返回包含原列表中所有元素的新列表
slice_0 = my_list[::]  # 输出: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# 获取索引 2 到 5 的元素
slice_1 = my_list[2:6]  # 输出: [2, 3, 4, 5]

# 获取从开始到索引 4 的元素
slice_2 = my_list[:5]  # 输出: [0, 1, 2, 3, 4]

# 获取从索引 5 到末尾的元素
slice_3 = my_list[5:]  # 输出: [5, 6, 7, 8, 9]

# 使用步长 2 获取元素
slice_4 = my_list[::2]  # 输出: [0, 2, 4, 6, 8]

# 使用负索引从末尾开始切片
slice_5 = my_list[-3:]  # 输出: [7, 8, 9]

# 使用负步长反转列表
slice_6 = my_list[::-1]  # 输出: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

切片的注意事项

  • 如果 startstop 超出列表范围,Python 会自动将其调整为有效范围。
  • 如果 step 为负数,切片会从右向左进行。
  • 切片操作不会修改原列表,而是返回一个新的列表。

切片的高级用法

# 使用切片修改列表的部分元素
my_list[2:5] = [10, 11, 12]  # 输出: [0, 1, 10, 11, 12, 5, 6, 7, 8, 9]

# 使用切片删除列表的部分元素
del my_list[2:5]  # 输出: [0, 1, 5, 6, 7, 8, 9]

错误原因

attempt to assign sequence of size 2 to extended slice of size 3 错误通常发生在尝试将一个长度为2的序列赋值给一个长度为3的扩展切片时。这种错误在Python中常见于列表、元组、NumPy数组等序列类型的操作中。

具体场景

假设有一个列表 a = [1, 2, 3, 4, 5],并尝试使用扩展切片对其进行赋值操作:

a[1:4:2] = [10, 20]

在这个例子中,a[1:4:2] 表示从索引1到索引4,步长为2的切片,其结果为 [2, 4],长度为2。然而,赋值操作 [10, 20] 的长度也是2,这与切片的长度匹配,因此不会引发错误。

但如果尝试将一个长度为3的序列赋值给这个切片:

a[1:4:2] = [10, 20, 30]

由于 a[1:4:2] 的长度为2,而 [10, 20, 30] 的长度为3,Python 会抛出 ValueError: attempt to assign sequence of size 3 to extended slice of size 2 错误。

解决方法

要解决这个问题,确保赋值操作中的序列长度与切片的长度匹配。例如:

a[1:4:2] = [10, 20]

或者调整切片的步长或范围,使其长度与赋值序列匹配:

a[1:5:2] = [10, 20, 30]

在这个例子中,a[1:5:2] 的切片结果为 [2, 4],长度为2,因此仍然会引发错误。正确的做法是:

a[1:6:2] = [10, 20, 30]

这样,a[1:6:2] 的切片结果为 [2, 4, 6],长度为3,与 [10, 20, 30] 的长度匹配,赋值操作将成功执行。

总结

确保赋值操作中的序列长度与切片的长度匹配是避免此类错误的关键。通过调整切片的范围或步长,可以确保两者长度一致,从而避免 ValueError 的发生。

通过掌握这些规则,可以灵活地使用切片操作来处理列表、字符串等序列类型的数据。

扩展

```python 
class Group:
    def __init__(self, group_name, company_name, staffs):
        self.group_name = group_name
        self.company_name = company_name
        self.staffs = staffs

    def __reversed__(self):
        return reversed(self.staffs)

    def __getitem__(self, item):
        cls = type(self)
        if isinstance(item, slice):
            return cls(group_name=self.group_name, company_name=self.company_name, staffs=self.staffs[item])
        elif isinstance(item, int):
            return cls(group_name=self.group_name, company_name=self.company_name, staffs=[self.staffs[item]])
        else:
            raise TypeError("Invalid argument type.")

    def __len__(self):
        return len(self.staffs)

    def __iter__(self):
        return iter(self.staffs)
 

代码说明

  • cls = type(self):获取当前实例的类。
  • isinstance(item, slice):检查 item 是否为 slice 类型。如果是,则返回一个新的实例,并传递 group_namecompany_name 参数。
  • elif isinstance(item, int):检查 item 是否为整数类型。如果是,则执行相应的逻辑。
  • else:处理其他情况。

进一步扩展

根据具体需求,可以在 elifelse 分支中添加更多的逻辑处理。例如:

cls = type(self)
if isinstance(item, slice):
    return cls(group_name=self.group_name, company_name=self.company_name)
elif isinstance(item, int):
    # 处理 item 为整数的情况
    return self._get_item_by_index(item)
else:
    # 处理其他情况
    raise TypeError(f"Unsupported type: {type(item)}")

在这个扩展版本中,_get_item_by_index 是一个假设的方法,用于根据索引获取项目。如果 item 的类型不被支持,则会抛出 TypeError 异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值