51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 766|回复: 0
打印 上一主题 下一主题

[资料] 详解python中的列表切片以及它与浅拷贝的关系(上)

[复制链接]
  • TA的每日心情
    无聊
    12 小时前
  • 签到天数: 1051 天

    连续签到: 1 天

    [LV.10]测试总司令

    跳转到指定楼层
    1#
    发表于 2022-7-5 11:10:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    前言
    在讲python中的列表之前,首先要引入字符串,在python中,字符串与列表都属于有序容器,有序意味着可以通过索引以及切片的方式对容器中的元素进行定位。另外,字符串与列表的区别在于字符串是不可变容器,意味着不能修改字符串的内容。
    字符串的索引与切片
    ·      字符串索引
    在python中,字符串被视为一种不可变序列,序列意味着可以使用索引以及切片来定位字符串中的元素,而不可变则意味着所有对字符串的修改操作都是非法的。
    索引是一种定位字符串中单个字符的做法,在python中,索引分为正序索引和逆序索引。而对于字符串这个具体的对象,索引是指字符串中的每个字符在字符串中的位置。正序索引从字符串起始处,从左往右分别给字符串中的字符编号,从0开始依次递增;逆序索引从字符串结尾处,从右往左分别给字符串中的字符编号,从-1开始依次递减。使用(字符串[索引下标])的方法,从字符串中定位单个字符。
    举例:对于"一起学习python自动化测试"这个字符串,我要定位它的第一个字符和最后一个字符,则可以采用如下的形式。
    1. str01 = "一起学习python自动化测试"
    2. print(str01[0])               
    3. print(str01[-1])
    复制代码
    上面程序的终端输出如下:


    复制代码
    注意:索引值不能超过字符串长度,否则会报IndexError
    1. <font face="微软雅黑">In [7]: print(str01[15])
    2. ---------------------------------------------------------------------------
    3. IndexError                                Traceback (most recent call last)
    4. <ipython-input-7-92262652de33> in <module>
    5. ----> 1 print(str01[15])

    6. IndexError: string index out of range</font>
    复制代码
    ·      字符串切片
    利用索引可以定位字符串中单个字符,当需要以某种形式获取字符串的子串时,切片就登场了。切片的语法是:容器[开始索引:结束索引:步长],表示从容器的开始索引处开始,到结束索引处为止,每隔一定的步长取出容器中的元素,并组合成一个新的容器,新容器的类型与原容器相同。这里的容器可以是python中任意类型的有序容器,包括字符串、列表、元组等等。开始索引默认为0,步长默认为1,如果不指定结束索引,则默认索引到容器的最后一个元素。步长为负数,表示从字符串末尾往前索引(逆序)。
    还是以上面索引的字符串为例,使用切片获取字符串的子串,用法如下:
    1. str01 = "一起学习python自动化测试"
    2. #   获取字符串的前4个字符
    3. str02 = str01[:4:]
    4. print(str02)
    5. #   获取字符串的第3到第10个字符
    6. str02 = str01[2:10:]
    7. print(str02)
    8. #        获取字符串的末尾5个字符
    9. str02 = str01[-5::]
    10. print(str02)
    11. #        获取字符串的前4个字符,步长为2
    12. str02 = str01[:4:2]
    13. print(str02)
    14. #        获取字符串的第3到第10个字符,步长为3
    15. str02 = str01[2:10:3]
    16. print(str02)
    17. #        逆序输出字符串的前4个字符
    18. str02 = str01[-12::-1]
    19. print(str02)
    20. #        逆序输出字符串的末尾5个字符
    21. str02 = str01[:-6:-1]
    22. print(str02)
    复制代码
    上面程序的终端输出分别如下:
    1. <font size="3" face="微软雅黑">一起学习
    2. 学习python
    3. 自动化测试
    4. 一学
    5. 学yo
    6. 习学起一
    7. 试测化动自</font>
    复制代码
    列表切片
    与字符串一样,列表也是python中的一种有序容器,并且容器的内容是可变的,可以使用索引及切片按照指定的规则从容器中获取或修改元素。

    假设有这样一个漫威电影宇宙,它有钢铁侠、美国队长、雷神、冬兵、蚁人、浩克、猩红女巫、女武神、星爵、格鲁特等英雄。我们给这个电影宇宙做一个列表,如下
    1. heroList01 = ["钢铁侠", "美国队长", "雷神", "冬兵", "浩克", "星爵", "格鲁特", "蚁人", "猩红女巫", "女武神"]
    复制代码
    ·      使用切片的方法从容器中获取元素
    与字符串操作类似,可以通过切片的方法获取列表中符合切片规则的元素,甚至获取整个列表的元素。列表的切片语法是:容器[开始索引:结束索引:步长]。
    o  获取列表中部分元素

    与字符串操作类似,我们可以获取列表中的前三个英雄、后五个英雄、第三到第七个英雄、逆序输出前三个/后五个英雄等等。
    1. #        获取列表中的前三个英雄
    2. heroList02 = heroList01[:3:]
    3. print(heroList02)
    4. #        获取列表中的后五个英雄
    5. heroList02 = heroList01[-5::]
    6. print(heroList02)
    7. #        获取列表的第三到第七个英雄
    8. heroList02 = heroList01[2:7:]
    9. print(heroList02)
    10. #        逆序输出列表前三个英雄
    11. heroList02 = heroList01[-8::-1]
    12. print(heroList02)
    13. #        逆序输出列表后五个英雄
    14. heroList02 = heroList01[:-6:-1]
    15. print(heroList02)
    复制代码
    上面程序的输出分别是:
    1. ['钢铁侠', '美国队长', '雷神']
    2. ['星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    3. ['雷神', '冬兵', '浩克', '星爵', '格鲁特']
    4. ['雷神', '美国队长', '钢铁侠']
    5. ['女武神', '猩红女巫', '蚁人', '格鲁特', '星爵']
    复制代码
    o  使用切片复制整个列表

    同样,我们可以使用切片复制整个列表,并且可以是以顺序或者逆序的方式复制。
    1. #        通过切片的形式复制列表
    2. heroList02 = heroList01[::]
    3. print(heroList02)
    4. #        通过切片的形式逆序复制列表
    5. heroList02 = heroList01[::-1]
    6. print(heroList02)
    复制代码
    上面程序的输出如下:
    1. ['钢铁侠', '美国队长', '雷神', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    2. ['女武神', '猩红女巫', '蚁人', '格鲁特', '星爵', '浩克', '冬兵', '雷神', '美国队长', '钢铁侠']
    复制代码
    使用切片时,python以浅拷贝的方式生成列表,并赋值给新对象。这与列表赋值不同,列表赋值仅仅是简单地将列表的首地址赋值给另外一个变量。我们用内存图的方式来呈现一下列表切片复制的整个过程
    ·      使用切片的方法修改容器中的元素
    由于列表是可变容器,我们可以修改列表中的元素,常规的修改方法是通过索引定位到列表中的某个元素然后加以修改。除此之外,我们可以使用切片的方法对列表中的一片特定区域做修改。
    还是以上面的漫威电影宇宙列表为例,我们使用三个新的英雄替换原先的英雄列表,新的英雄分别是幻视、鹰眼、蜘蛛侠。有几种替换方案:

    o  三换三,替换后,列表的英雄数量还是10个。
    1. originList = ["钢铁侠", "美国队长", "雷神", "冬兵", "浩克", "星爵", "格鲁特", "蚁人", "猩红女巫", "女武神"]
    2. heroList02 = ["幻视", "鹰眼", "蜘蛛侠"]
    3. heroList01 = originList[:]
    4. #        使用切片的方式替换heroList01的前三个元素
    5. heroList01[:3] = heroList02
    6. print(heroList01)
    7. heroList01 = originList[:]
    8. #        使用切片的方式替换heroList01的第5-7个元素
    9. heroList01[4:7] = heroList02
    10. print(heroList01)
    11. heroList01 = originList[:]
    12. #        使用切片的方式替换heroList01的末尾三个元素
    13. heroList01[-3:] = heroList02
    14. print(heroList01)
    15. heroList01 = originList[:]
    16. #        使用切片的方式替换heroList01的末尾三个元素,并且是逆序
    17. heroList01[:-4:-1] = heroList02
    18. print(heroList01)
    19. heroList01 = originList[:]
    20. #        使用切片的方式替换heroList01的前三个元素,并且是逆序
    21. heroList01[-8::-1] = heroList02
    22. print(heroList01)
    复制代码
    上面程序的输出如下:
    1. ['幻视', '鹰眼', '蜘蛛侠', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    2. ['钢铁侠', '美国队长', '雷神', '冬兵', '幻视', '鹰眼', '蜘蛛侠', '蚁人', '猩红女巫', '女武神']
    3. ['钢铁侠', '美国队长', '雷神', '冬兵', '浩克', '星爵', '格鲁特', '幻视', '鹰眼', '蜘蛛侠']
    4. ['钢铁侠', '美国队长', '雷神', '冬兵', '浩克', '星爵', '格鲁特', '蜘蛛侠', '鹰眼', '幻视']
    5. ['蜘蛛侠', '鹰眼', '幻视', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    复制代码
    由上面程序输出可以看出,使用切片的方式可以将列表1的部分元素批量替换成列表2的元素。我们以替换前三个元素为例,研究一下切片过程中的内存布局变化
    1. heroList01 = ["钢铁侠", "美国队长", "雷神", "冬兵", "浩克", "星爵", "格鲁特", "蚁人", "猩红女巫", "女武神"]
    2. heroList02 = ["幻视", "鹰眼", "蜘蛛侠"]
    3. print("heroList01 的内容是:{}".format(heroList01))
    4. print("heroList01 的地址是:{}".format(hex(id(heroList01))))
    5. print("originList 第一个元素的地址是:{}".format(hex(id(originList[0]))))
    6. print("heroList01 第一个元素的地址是:{}".format(hex(id(heroList01[0]))))
    7. print("heroList02 第一个元素的地址是:{}".format(hex(id(heroList02[0]))))
    8. heroList01[:3] = heroList02
    9. print("heroList01 的内容是:{}".format(heroList01))
    10. print("heroList01 的地址是:{}".format(hex(id(heroList01))))
    11. print("originList 第一个元素的地址是:{}".format(hex(id(originList[0]))))
    12. print("heroList01 第一个元素的地址是:{}".format(hex(id(heroList01[0]))))
    13. print("heroList02 第一个元素的地址是:{}".format(hex(id(heroList02[0]))))
    复制代码
    上面程序的输出如下:
    1. heroList01 的内容是:['钢铁侠', '美国队长', '雷神', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    2. heroList01 的地址是:0x1fab98ec908
    3. originList 第一个元素的地址是:0x1fab86f84b0
    4. heroList01 第一个元素的地址是:0x1fab86f84b0
    5. heroList02 第一个元素的地址是:0x1fab98f7e10
    6. heroList01 的内容是:['幻视', '鹰眼', '蜘蛛侠', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    7. heroList01 的地址是:0x1fab98ec908
    8. originList 第一个元素的地址是:0x1fab86f84b0
    9. heroList01 第一个元素的地址是:0x1fab98f7e10
    10. heroList02 第一个元素的地址是:0x1fab98f7e10
    复制代码
    可以看到,当切片运算符[:]出现在赋值运算符=左边时,对列表的修改操作并不会产生新列表,而是在原来的列表上面修改,修改以后,列表中的元素被替换。使用内存图描述如下:
    o  N换三,替换后,列表的英雄数量大于或者小于10个。
    1. originList = ["钢铁侠", "美国队长", "雷神", "冬兵", "浩克", "星爵", "格鲁特", "蚁人", "猩红女巫", "女武神"]
    2. heroList02 = ["幻视", "鹰眼", "蜘蛛侠"]
    3. heroList01 = originList[:]
    4. #        保持原列表不变,在原列表的开头插入新列表
    5. heroList01[:0] = heroList02
    6. print(heroList01)
    7. heroList01 = originList[:]
    8. #        保持原列表不变,在原列表的中间插入新列表
    9. heroList01[4:4] = heroList02
    10. print(heroList01)
    11. heroList01 = originList[:]
    12. #        保持原列表不变,在原列表的末尾插入新列表
    13. heroList01[10:] = heroList02
    14. print(heroList01)
    15. heroList01 = originList[:]
    16. #        1换3
    17. heroList01[:1] = heroList02
    18. print(heroList01)
    19. heroList01 = originList[:]
    20. #        5换3
    21. heroList01[:5] = heroList02
    22. print(heroList01)
    23. heroList01 = originList[:]
    24. #        10换3
    25. heroList01[:] = heroList02
    26. print(heroList01)
    复制代码
    上面程序的输出如下:
    1. ['幻视', '鹰眼', '蜘蛛侠', '钢铁侠', '美国队长', '雷神', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    2. ['钢铁侠', '美国队长', '雷神', '冬兵', '幻视', '鹰眼', '蜘蛛侠', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    3. ['钢铁侠', '美国队长', '雷神', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神', '幻视', '鹰眼', '蜘蛛侠']
    4. ['幻视', '鹰眼', '蜘蛛侠', '美国队长', '雷神', '冬兵', '浩克', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    5. ['幻视', '鹰眼', '蜘蛛侠', '星爵', '格鲁特', '蚁人', '猩红女巫', '女武神']
    6. ['幻视', '鹰眼', '蜘蛛侠']
    复制代码
    进一步对上面程序的列表地址以及各个元素的地址研究后发现,不管是在列表中插入新列表,还是1换3、5换3、10换3,均没有销毁heroList01,而只是简单地将heroList01的列表节点重定向到新的列表元素上,并在重定向的过程中新增或者删除旧的列表节点。









    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-26 21:59 , Processed in 0.066316 second(s), 24 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表