Python中的切片

Python 小记 2019-02-05 3696 字 1405 浏览 点赞

前言

一直想把Python切片的知识总结,但拖延至今方才摁键。起因是室友接受了导师给的课题,机器学习相关,之前他一直实习Java,现在要学Python了。有一天他发信息问我关于切片的问题,我竟不能十分肯定的回答。惭愧!但不得不说,Python切片中的Tips是我之前不曾见过,也自然不曾使用的,今日就着外面世界的烟火炮竹,把眼界大开。

切片

切片的完整格式:[start:end:step],通常我们只用到startend

这里引用Bobby老师的一段话,对切片格式简单介绍:

其中,第一个数字start表示切片开始位置,默认0;
第二个数字end表示切片截止(但不包含)位置(默认为列表长度);
第三个数字step表示切片的步长(默认为1)。
当start为0时可以省略,当end为列表长度时可以省略,
当step为1时可以省略,并且省略步长时可以同时省略最后一个冒号。
另外,当step为负整数时,表示反向切片,这时start应该比end的值大才行。

如果存在一个列表lyst = [1, 2, 3, 4],那么lyst[2:4]的值为[3, 4]。对Python来说,切片并非列表专利,元组也可以做切片操作:

In [0]: tuple_ = (1, 2, 3, 4)

In [1]: tuple_[2:4]
Out[1]: (3, 4)

可看到一个现象,列表的切片类型是列表,元组的切片类型还是元组。

关于切片的一些常见使用如下:

In [0]: lyst = [1, 2, 3, 4]

In [1]: lyst[::]
Out[1]: [1, 2, 3, 4]

In [2]: lyst[::-1]  # 反向序列
Out[2]: [4, 3, 2, 1]

In [3]: lyst[::2]  # 等同“lyst[0::2]”。从索引0开始,每间隔一个元素取一个值。
Out[3]: [1, 3]

In [4]: lyst[1::2]  # 从索引1开始,每间隔一个元素取一个值。
Out[4]: [2, 4]

In [5]: lyst[1:100]  # end >= 列表长度时,可以省略end。等同“lyst[1:]”
Out[5]: [2, 3, 4]

In [6]: lyst[100:]  # 当star >= 列表长度时,切片操作得到一个空列表
Out[6]: []

Tips

以下以lyst = [1, 2, 3, 4]为例(下面操作中,等号右边必须是可迭代类型):

  • 在列表最左边插入元素:

    In [0]: lyst[:0] = ["z", "t", "y"]
    
    In [1]: lyst
    Out[1]: ['z', 't', 'y', 1, 2, 3, 4]
    
    In [2]: lyst[:0] = "512"
    
    In [3]: lyst
    Out[3]: ['5', '1', '2', 'z', 't', 'y', 1, 2, 3, 4]
  • 在列表最右边插入元素:

    In [0]: lyst[100:] = ["z", "t", "y"]
    
    In [1]: lyst
    Out[1]: [1, 2, 3, 4, 'z', 't', 'y']
    
    In [2]: lyst[len(lyst):] = [512]
    
    In [3]: lyst
    Out[3]: [1, 2, 3, 4, 'z', 't', 'y', 512]
  • 在列表中间插入元素:

    In [0]: lyst[2:2] = ["zty"]  # 将等号右边列表中的元素从索引为2的位置开始插入
    
    In [1]: lyst
    Out[1]: [1, 2, 'zty', 3, 4]  # "zty"的索引为2
    
    In [2]: lyst[1:1] = "gyx"  # 注意与 ["gyx"] 的区别
    
    In [3]: lyst
    Out[3]: [1, 'g', 'y', 'x', 2, 'zty', 3, 4]
  • 元素替换:

    In [0]: lyst[1:2] = "z"
    
    In [1]: lyst
    Out[1]: [1, 'z', 3, 4]
    
    In [2]: lyst[2:] = [512, 1024, 2048]
    
    In [3]: lyst
    Out[3]: [1, 'z', 512, 1024, 2048]
  • 隔位替换(等号右边的序列长必须等于等号左边的切片长):

    In [0]: lyst[::2] = [0] * 2
    
    In [1]: lyst
    Out[1]: [0, 2, 0, 4]
    
    In [2]: lyst[1::2] = "ty"
    
    In [3]: lyst
    Out[3]: [0, 't', 0, 'y']
  • 删除元素:

    In [0]: lyst[:2] = []  # 这种方式只能删除连续元素
    
    In [1]: lyst
    Out[1]: [3, 4]

    等同:

    In [0]: del lyst[:2]
    
    In [1]: lyst
    Out[1]: [3, 4]

    按一定规律删除间隔的元素:

    In [0]: del lyst[::2]  # 删除元素1,3
    
    In [1]: lyst
    Out[1]: [2, 4]

实现切片

Python中,如果希望对象可以使用切片操作,需要实现__getitem__方法。

from numbers import Integral

class Room(object):
    def __init__(self, people=None):
        people = people or []
        self.people = people

    def __getitem__(self, item):
        print("item 的类型是 ", type(item))
        # 获取索引位置的值
        if isinstance(item, Integral):
            return self.people[item]

        # 确保切片出来的对象类型是切片之前的类型
        return self.__class__(self.people[item])

    def __str__(self):
        return str(self.people)

if __name__ == "__main__":
    room = Room(["bobby", "lily", "Joe", "Green"])
    print(type(room[3]))

    print(room[1:3])
    print(type(room[1:3]))

# 输出:
item 的类型是  <class 'int'>
<class 'str'>
item 的类型是  <class 'slice'>
['lily', 'Joe']
item 的类型是  <class 'slice'>
<class '__main__.Room'>

可见,当括号中内容不是一个数值时,解释器会取出括号中的内容用来实例化slice类型的对象,然后传入__getitem__方法中。此时,对item打印,输出如下:

# room[1:3]
slice(1, 3, None)

# room[1:4:2]
slice(1, 4, 2)

也就是说,slice类的初始化参数依次对应了start,end,step。

感谢



本文由 Guan 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论