• 【Python】第四课 列表,元组和字符串的使用


    4.1 列表

    python中的列表类似于Java中的Object的list集合,可以在同一个列表中存放不同数据类型的数据。

    4.1.1 创建列表

    创建列表和创建普通变量一样,用中括号括一堆数据就可以了,数据之间用逗号隔开:

    1. # 列表的使用
    2. numbers=[1,2,3,4,5]
    3. # 列表中的数据的数据类型可以不一致,也可以列表中嵌套列表使用
    4. texts=["图片",3.14,True,1000,"abc",[1,2,3]]
    5. # 列表的定义也可以为空,后期再进行存入数据
    6. empty=[]

    4.1.2 向列表中添加元素

    列表相当灵活,所有它的内存大小是不固定的,向列表中添加元素,可以使用append()方法,

    1. # 列表中添加元素
    2. numbers.append(6)
    3. print(numbers) #输出结果:[1, 2, 3, 4, 5, 6]

    但只能一个个元素添加,而不能一次添加多个,则需要使用extend()方法:

    1. # 列表中添加多个元素
    2. numbers.extend([7,8,9])
    3. print(numbers) #输出结果:[1, 2, 3, 4, 5, 6, 7, 8, 9]

    该方法实际上是将一个列表追加在原列表之后,扩充了原列表。

    向列表中任意位置插入元素:

    1. # 任意位置添加元素
    2. # 下标为0的位置上添加0
    3. numbers.insert(0,0)
    4. print(numbers)
    5. # 下标为0的位置上添加一个子列表
    6. numbers.insert(0,[-2,-1])
    7. print(numbers)

    但不能给某一个位置上插入多个元素

    4.1.3 从列表中获得元素

    python的列表取值和Java的数组或者list集合是一样的,通过下标来获得单个元素,列表的索引值是从0开始的。

    1. # 根据下标获得列表中元素
    2. names=["张三","李四","王五","赵六"]
    3. print(names[0]) #输出结果:张三
    4. print(names[3]) #输出结果:赵六
    5. # 修改列表中指定的元素,元素之间交换数据
    6. names[1],names[3]=names[3],names[1]
    7. print(names) #输出结果:['张三', '赵六', '王五', '李四']

    4.1.4 从列表中删除元素

    列表删除元素,这里介绍三种方法:remove(),del和pop().

    1. # 使用remove()方法根据内容删除列表中的元素
    2. numbers.remove(2)
    3. print(numbers)

    该方法只能删除指定的单个元素。

    1. # 使用del方法根据下标删除列表中的元素
    2. del numbers[0]
    3. print(numbers)
    4. # 使用del方法删除整个列表
    5. del numbers
    1. # 使用pop方法根据下标删除列表中的元素
    2. # 该方法默认是将列表中末尾的元素取出来,并从列表中删除
    3. n=numbers.pop()
    4. print("从列表中取出的元素为:%d"%n)
    5. print(numbers)
    6. # 指定下标取出元素,并从列表中删除
    7. # 取出下标为5的元素
    8. n=numbers.pop(5)
    9. print("从列表中取出的元素为:%d"%n)
    10. print(numbers)

    4.1.5 列表分片

    利用索引值每次可以从列表获取一个元素,但是这个效率还是太慢,如果能一次性获得更多的元素那就更好,这里列表的分片就能简单方便的实现:

    1. # 列表分片
    2. names=["张三","李四","王五","赵六"]
    3. print(names[:2]) # ['张三', '李四']
    4. print(names[0:2])# ['张三', '李四']
    5. print(names[1:2])# ['李四']
    6. print(names[1:])# ['李四', '王五', '赵六']
    7. print(names[:])# ['张三', '李四', '王五', '赵六']

    通过以上的案例可以总结出,列表的分片是包头不包尾,就是根据开始的下标值获得元素,一直到结束的下标位置,但是不会输出结束下标位置的元素。如果没有开始位置,python会默认开始位置为0,同样道理,如果要得到从指定索引值到列表末尾的所有元素,把结束位置省去即可。如果没有放入任何索引值,而只有一个冒号,将得到整个列表的拷贝。

    再次强调:列表分片就是建立原列表的一个拷贝,一个副本,所有如果你想对列表做出某些修改,但同时还想保持原本的哪个列表,那么直接使用分片的方法来获得拷贝就很方便了。

    列表分片实际上有三个参数,第一个参数表示开始的索引下标,第二个参数表示结束的索引下标,第三个参数表示步长,用于从列表中根据下标的迭代的增值。

    1. # 取出列表中步长为2的值
    2. numbers=[1,2,3,4,5]
    3. print(numbers[0:9:2]) # [1, 3, 5]
    4. # 当步长为负数时,表示倒序获取
    5. print(numbers[::-1]) #[5, 4, 3, 2, 1]
    6. print(numbers[::-2])#[5, 3, 1]

    对列表进行分片后的赋值和原列表的直接赋值的操作情况是不同的。

    1. #分片处理,是对原列表的拷贝,而不对原列表造成影响
    2. list3=[1,1,22,3,4,5,33]
    3. x1=list3[:]
    4. x2=list3
    5. print("x1是对list3列表的分片后的存储:%s"%x1)
    6. print("x2是对list3列表的引用地址的存储:%s"%x2)
    7. # 对原列表进行从小到大排序,并观察x1和x2列表的变化
    8. list3.sort()
    9. print("原列表排序后%s"%list3)#原列表排序后[1, 1, 3, 4, 5, 22, 33]
    10. print("x1列表的变化%s"%x1)#x1列表的变化[1, 1, 22, 3, 4, 5, 33]
    11. print("x2列表的变化%s"%x2)#x2列表的变化[1, 1, 3, 4, 5, 22, 33]
    12. #通过观察可发现,分片处理是对原列表的拷贝,不受元列表的影响,是独立的。
    13. #但x2列表是被原列表的地址赋值,也就是说list3与x2都指向原列表,属于同一块内存。

    4.1.6 列表的常用操作

    列表可以用来比较大小,也可以用来做加减乘除的快速生成列表操作。

    1. # 比较两个列表的大小
    2. x1=[123,234,345]
    3. x2=[234,123,345]
    4. print(x1>x2) #False

    列表之间的比较与Java中字符串之间的比较是类似的,取各自的第一个元素进行比较,如果第一个元素的结果是True才会去比较第二个元素,如果第一个元素为False,那么不再继续比较,直接得到结果为False。

    1. # 两列表做+法拼接
    2. x3=x1+x2
    3. print(x3)# [123, 234, 345, 234, 123, 345]
    4. # 但需要需要给列表中添加单个元素,不能使用加法连接符,只能使用insert或者append方法
    1. #快速创建列表的模拟数据
    2. a1=[8]
    3. a1=a1*4
    4. print(a1) # [8, 8, 8, 8]
    1. #判断列表中是否存在某个元素
    2. print(123 in x1) # True
    3. print(123 not in x1) #False
    4. print(123 in x2[1]) # True
    5. print(123 not in x2[1]) #False

    关键字in和not in只能判断一个层次的成员关系,与break,continue的概念是一致的,如果出现列表嵌套列表,该关键字是判断不了多层嵌套内部的元素是否存在。

    4.1.7 列表的其他常用方法

    以上我们学习了很多列表的增删改查的方法,其实列表还有很多方法,我们可以使用dir()函数将列表中的方法都列举出来。

    1. #查看列表中的所有可用方法
    2. print(dir(list)) #list就是列表的类名

    运行结果:

    ['add', 'class', 'contains', 'delattr', 'delitem', 'dir', 'doc', 'eq', 'format', 'ge', 'getattribute', 'getitem', 'gt', 'hash', 'iadd', 'imul', 'init', 'init_subclass', 'iter', 'le', 'len', 'lt', 'mul', 'ne', 'new', 'reduce', 'reduce_ex', 'repr', 'reversed', 'rmul', 'setattr', 'setitem', 'sizeof', 'str', 'subclasshook', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']

    以后可以通过dir()方法来查看某一个对象的常用方法。

    接着我们再来学习列表中的几个常用方法:

    count()这个方法的作用是计算它的参数在列表中出现的次数:

    1. # 查找列表中某个元素出现的次数
    2. list1=[1,1,2,3,4,8,13,21]
    3. print("1在列表中出现的次数为:%d"%list1.count(1))# 1在列表中出现的次数为:2

    index()找出列表中某个元素在列表中的下标索引位置:

    1. # 获得元素索引位置
    2. print(list1.index(8)) # 5
    3. #找出第一个1的索引位置
    4. print(list1.index(1)) # 0
    5. #找出第二个1的索引位置
    6. print(list1.index(1,list1.index(1)+1,len(list1))) #1
    7. #index函数的第一个参数表示要查找的元素,第二个参数表示从列表中开始搜索的索引值
    8. #第三个参数表示结束搜索的索引值

    使用index函数时,如果搜索不到该元素,则会使程序报错。

    reverse()方法的作用是将整个列表原地翻转,也就是倒序排列。注意这个倒序不是拷贝副本,而是原列表进行倒序。

    1. #将列表进行倒序
    2. list1.reverse()
    3. print(list1) # [21, 13, 8, 4, 3, 2, 1, 1]

    sort()方法将乱序的列表进行排序,默认为从小到大排序

    1. #列表排序,默认为从小到大排序
    2. list2=[2,3,42,54,5,12,9,100]
    3. list2.sort()
    4. print(list2)# [2, 3, 5, 9, 12, 42, 54, 100]
    5. #从大到小排序
    6. list2.sort(reverse=True)
    7. print(list2)

    其实sort函数中有三个参数,第一个参数func用于设置排序的算法,默认为归并排序,属于分治算法。第二个参数key用于设置关键字,第三个参数reverse用于设置是升序排序还是降序排序。

    4.2 元组

    Python中的元组类似与Java中的数组,也类似于字符串,长度是固定的,不能进行随意的删减添加元素。

    4.2.1 创建和访问元组

    元组的创建大部分时候用的是小括号,在特殊情况创建的形式会不同。

    1. # 元组的创建和访问
    2. tuple1=(1,2,3,4,5,6,7,8)
    3. print(tuple1)#(1, 2, 3, 4, 5, 6, 7, 8)
    4. # 根据索引值获得元组中的元素
    5. print(tuple1[2],tuple1[4],tuple1[6])#3 5 7
    6. #元组中使用分片
    7. print(tuple1[3:])#(4, 5, 6, 7, 8)
    8. print(tuple1[:6])#(1, 2, 3, 4, 5, 6)

    元组的创建并不是完全由(小括号)决定的,而是有(,)逗号决定的。

    1. # 初始化定义元组
    2. temp=(1)
    3. print(type(temp))#显示是,说明小括号并不是定义元组的关键写法
    4. temp=1,
    5. print(type(temp))#显示是,说明逗号才是定义元组的关键写法
    6. #当需要初始化一个空元组的时候,可以使用小括号表示
    7. temp=()
    8. print(type(temp))#
    9. #当定义有值的元组时,有以下两种用法
    10. temp=(1,)
    11. print(type(temp))#输出结果为:
    12. temp=1,
    13. print(type(temp))#输出结果为:
    14. #快速生成元组数据
    15. temp=8,
    16. temp=temp*8
    17. print(temp)#(8, 8, 8, 8, 8, 8, 8, 8)

    4.2.2 更新和删除元组

    元组不能和列表的使用一样在原列表中进行修改和删除数据,元组是固定的,那么如果要修改和删除数据,只能和字符串拼接的操作一样去处理元组的数据的更新。

    1. # 元组的修改和删除
    2. texts=("苹果","香蕉","西瓜","脐橙")
    3. #该元组中香蕉的后面插入一个榴莲,使用+加法连接符将三个元组连接起来
    4. texts=texts[:2]+("榴莲",)+texts[2:]
    5. print(texts)# ('苹果', '香蕉', '榴莲', '西瓜', '脐橙')
    6. #将元组中的西瓜删除
    7. texts=texts[:3]+texts[4:]
    8. print(texts)# ('苹果', '香蕉', '榴莲', '脐橙')
    9. #如果要删除整个元组,只需要del即可
    10. del texts

    在日常生活中,很少使用del去删除整个元组,因为Python的回收机制会在这个元组不再被使用到的时候自动删除。在元组中,也可以正常使用拼接操作符,关系运算符,逻辑运算符,算术运算符以及in,not in。

    4.3 字符串

    在学习列表和元组的知识中,我们掌握了一个很重要的知识就是分片,实际上字符串和元组很像,因此字符串中也能使用分片技术。在Python中是没有字符这个类型的,单个字符只会认为是长度为1的字符串。

    1. #字符串的使用
    2. text="hello python!!!"
    3. print(text[6:])#python!!!
    4. #根据索引值获得单个字符串
    5. print(text[6])#p
    6. #在字符串中插入子字符串
    7. text=text[:6]+"P"+text[7:]
    8. print(text)#hello Python!!!

    字符串的更新与元组的更新是一致的,将原字符串组合成一个新的字符串,存储在新的内存中,原字符串的内存会被Python的垃圾回收机制进行自动回收。

    4.3.1 常用内置方法

     

    1. # 将字符串全部变为小写字母
    2. s1="I'm Chinese"
    3. s1=s1.casefold()
    4. print(s1)#i'm chinese
    5. # 查找某个子字符串在字符串中出现的次数,该方法是区分大小写的
    6. s2="aBabAbababAABBAB"
    7. print(s2.count("ab",0,len(s2)))# 3
    8. # find()和index()都是用来查找子字符串在原字符串中的索引值
    9. #到哪前者如果没找到则返回值为-1,后者则会直接报错,后期可以通过异常捕获处理
    10. print(s2.find("AA",0,len(s2)))#10
    11. print(s2.index("BB",0,len(s2)))#12
    12. #给字符串中插入分隔符
    13. s3="I is boy"
    14. s3="_".join(s3)
    15. print(s3)#I_ _i_s_ _b_o_y
    16. #使用join()方法可以快速的将列表或者元组转换成字符串格式,做大量的字符串的拼接
    17. print(" ".join(["abc","123","456","True","3.14","123"]))#abc 123 456 True 3.14 123
    18. print(" ".join(("abc","123","456","True","3.14","123")))#abc 123 456 True 3.14 123
    19. #将原字符串中某个子字符串查找后使用新的子字符串进行替换
    20. s4="I Love You"
    21. print(s4.replace("You","girl"))# I Love girl
    22. # 将字符串按某个分隔符进行分割成列表,该方法与join()方法是刚好相反
    23. s5="I_ _i_s_ _b_o_y"
    24. s5=s5.split("_")
    25. print(s5)# ['I', ' ', 'i', 's', ' ', 'b', 'o', 'y']

    4.3.2 格式化

    这里的格式化其实类似于占位符,将不确定的数据用某种符号格式进行占位,等确定了数据后将数据替换占位符。

    1. #格式化
    2. s6="{0} Love {1}"
    3. print(s6.format("You","Me"))#You Love Me
    4. print(s6.format("boy","girl"))#boy Love girl
    5. s7="{a} eat {b} and {c}"
    6. print(s7.format(a="I",b="apple",c="banana"))#I eat apple and banana
    7. #通过以上代码的演示用数字作为占位符是直接按顺序替换即可,用字母作为占位符时,替换的时候一定需要加上占位符的变量名
    8. #python中可以将两种用法综合使用,但是数字的占位符一定要放置在字母占位符之前使用,否则会产生语法异常
    9. #打印出大括号,需要嵌套一层大括号,这里就不再表示占位符了
    10. print("{{0}}".format())#{0}
    11. #控制浮点数的位数,表示为1位整数,两位小数,需要注意的是小数前需要添加.,表示四舍五入保留两位小数
    12. print("{0}:{1:.2f}".format("圆周率",3.1415926))

    格式化操作符: %

    符号含义
    %c格式化字符及其ASCII码
    %s格式化字符串
    %d格式化整数
    %o格式化无符号八进制数
    %x格式化无符号十六进制数
    %X格式化无符号十六进制数(大写)
    %f格式化浮点数字,可指定小数点后的精度
    %e用科学计数法格式化浮点数
    %E用科学计数法格式化浮点数
    %g根据值的大小决定使用%f还是%e
    %G根据值的大小决定使用%f还是%E
    1. #将字符a的ASCII码的值97转换成字符
    2. print("ASCII码为%d对应的字符是%c"%(97,97))#ASCII码为97对应的字符是a
    3. print("%c%c%c%c"%(70,105,115,104))#Fish
    4. print("%d转换成八进制为%o"%(123,123))#123转换成八进制为173
    5. print("%d转换成十六进制为%x"%(123,123))#123转换成十六进制为7b
    6. print("%f用科学计数法表示%e"%(149500000,149500000))#149500000.000000用科学计数法表示1.495000e+08
    7. print("%f用科学计数法表示%E"%(149500000,149500000))#149500000.000000用科学计数法表示1.495000E+08

    格式化操作符的辅助指令

    符号含义
    m.nm是显示的最小总长度,n是小数点后的位数
    -结果左对齐
    +在整数前面显示加号
    #在八进制数前面显示“0o”,在十六进制数前面显示“0x”或“0X”
    0显示的数字前面填充“0”代替空格
    1. # 将该浮点数保留5位整数,1位小数进行四舍五入的浮点数
    2. print("%5.1f"%27.658)#27.7
    3. # 将该浮点数保留1位整数,2位小数进行四舍五入的科学计数法
    4. print("%.2e"%27.658)#2.77e+01
    5. # 将数字保留10位数的整数,默认靠右对齐,前面以空白填充
    6. print("%10d"%27.658)# 27
    7. # 将数字保留10位数的整数,靠左对齐,后面以空白填充
    8. print("%-10d"%27.658)#27
    9. # 将数字保留10位数的整数,默认靠右对齐,前面以0填充
    10. print("%010d"%27.658)#0000000027
    11. # 将十进制转换成十六进制,并添加进制符号
    12. print("%#X"%100)#0X64

    转义字符及含义

    符号说明符号说明
    \'单引号\r回车符
    \"双引号\f换页符
    \a发出系统响铃声\o八进制数代表的字符
    \b退格符\x十六进制数代表的字符
    \n换行符\0表示一个空格符
    \t横向制表符(Tab)\\反斜杠
    \v纵向制表符

    4.4 序列

    这里对列表,元组,字符串之间的共性做一个汇总,并使用常用的几个方法对列表,元组和字符串之间的互相转换进行操作。

    • 都可以通过索引得到每一个元素

    • 默认索引值总是从0开始

    • 可以通过分片的方法得到一个范围内的元素的集合

    • 有很多共同的操作符

    下面介绍一下常用BIF(内建方法):

    4.4.1 list([iterable])

    该方法可以将字符串,元组转换成列表

    1. #创建空列表
    2. list1=list()
    3. print(list1)#[]
    4. #将字符串转换为列表
    5. list2=list("abcdefg")
    6. print(list2)#['a', 'b', 'c', 'd', 'e', 'f', 'g']
    7. #将元组转换为列表
    8. list3=list((1,2,3,4,5,6,7))
    9. print(list3)#[1, 2, 3, 4, 5, 6, 7]

    4.4.2 tuple([iterable])

    该方法可以将字符串,列表转换成元组

    1. #创建空元组
    2. t1=tuple()
    3. print(t1)#[]
    4. #将字符串转换为元组
    5. t2=tuple("abcdefg")
    6. print(t2)#('a', 'b', 'c', 'd', 'e', 'f', 'g')
    7. #将列表转换为元组
    8. t3=tuple([1,2,3,4,5,6,7])
    9. print(t3)#(1, 2, 3, 4, 5, 6, 7)

    4.4.3 str(obj)

    将obj对象转换为字符串,这里包括各种数据类型,在前面已介绍过。

    1. #将浮点型转换成字符串
    2. r1=str(3.14)
    3. print(r1)

    4.4.4 len(sub)

    该方法用于获得列表,元组或者字符串的长度

    1. #获得字符串长度
    2. str1="aaaaaaaaaaa"
    3. print(len(str1))
    4. #获得列表长度
    5. list1=["a",123,True]
    6. print(len(list1))
    7. #获得元组长度
    8. tuple1="a","b","c","d"
    9. print(len(tuple1))

    4.4.5 Max(……)和Min(……)

    该方法用于获得字符串,列表,元组中最大值和最小值的元素,一般操作在数字上比较多。但一定要保证每一个元素的数据类型是一致的。

    1. # 获得最大值,最小值
    2. list1=[1,18,13,0,-98,34,54,76,32]
    3. print("列表中最大值为:%d,最小值为:%d"%(max(list1),min(list1)))
    4. str1="I Love fishc.com"
    5. print("字符串中最大值为:%s,最小值为:%s"%(max(str1),min(str1)))
    6. t1=(5,8,1,13,5,29,10,7)
    7. print("元组中最大值为:%s,最小值为:%s"%(max(t1),min(t1)))

    运行结果:

    列表中最大值为:76,最小值为:-98 ​ 字符串中最大值为:v,最小值为: ​ 元组中最大值为:29,最小值为:1

    4.4.6 sum(iterable[,start])

    该方法用于做累加求和。

    1. #累加求和
    2. list1=[1,2,3,4,5]
    3. print(sum(list1))#15
    4. print(sum(list1,100))#115

    4.4.7 sorted(iterable,key=none,reverse=False)

    该方法用于返回一个排序的列表,与sort()内建方法实现的效果是一致的,但sort()函数是将原列表进行排序,而该方法是拷贝一个副本进行排序,原列表不受影响。

    1. #列表排序
    2. list1=[1,18,13,0,-98,34,54,76,32]
    3. #将列表分片获得副本
    4. list2=list1[:]
    5. #将原列表进行sort内建方法排序
    6. list1.sort()
    7. print(list1)#[-98, 0, 1, 13, 18, 32, 34, 54, 76]
    8. list3=sorted(list2)
    9. print(list3)#[-98, 0, 1, 13, 18, 32, 34, 54, 76]
    10. print(list2)#[1, 18, 13, 0, -98, 34, 54, 76, 32]

    通过输出结果可以发现,sort内建函数直接将list1列表进行排序了,而通过分片获得的副本list2在通过sorted函数做排序之后,又获得一个副本list3,其原本list2并没有发现变化。

    4.4.8 reversed(sequence)

    该方法用于返回逆向迭代序列的值,其效果和reverse内建函数的效果是一致的,都是将列表数据进行倒序输出,但内建函数是将原列表进行倒序,而该方法是拷贝一个副本进行倒序,原列表并不受影响,但倒序后获得的不是列表而是迭代对象,不能进行直接输出。

    1. #列表倒序
    2. print(reversed(list1))#
    3. for i in reversed(list1):
    4. print(i,end=",")
    5. #76,54,34,32,18,13,1,0,-98,

    通过输出结果发现反转后获得的是迭代对象,并不是列表也不是元组,因此输出的时候是一个列表反转后的迭代对象,打印的是地址编码。只能通过循环遍历获得,并在每次输出后面填逗号拼接。

    4.4.9 enumerate(iterable)

    该方法是将字符串,列表或者元组转换成枚举类型的迭代对象输出,该迭代由索引值和元素组成。

    1. #转换成枚举类型迭代输出
    2. str1="Fish"
    3. for i in enumerate(str1):
    4. print(i)
    5. for i in enumerate(list1):
    6. print(i)

    第一个循环输出结果为:

    (0, 'F') (1, 'i') (2, 's') (3, 'h')

    第二个循环输出结果为:

    (0, -98) (1, 0) (2, 1) (3, 13) (4, 18) (5, 32) (6, 34) (7, 54) (8, 76)

    4.4.10 zip(iter1[,iter2[……]])

    该方法用于返回由各个可迭代参数共同组成的元组。例如列表,字符串,元组进行每项组合压缩成一个元素显示,类似于打包,但要求项数保持一致。

    1. #数据打包
    2. list1=[2,4,6,8,10]
    3. str1="abcde"
    4. t1=1,3,5,7,9
    5. for i in zip(list1,str1,t1):
    6. print(i)

    结果为:

    (2, 'a', 1) (4, 'b', 3) (6, 'c', 5) (8, 'd', 7) (10, 'e', 9)

  • 相关阅读:
    ECCV 2022 | 悉尼大学提出:绝对尺度感知,鲁棒,以及可泛化的自监督单目深度估计网络DynaDepth
    PCIe带宽性能分析
    R语言ggplot2可视化:使用ggpubr包的ggboxplot函数可视化分组箱图、使用fill_palette函数改变可视化图像的填充色
    面试java框架-Spring
    Unity 2021 请求 Android 12 读取本地文件权限
    windows10下whisper的安装使用和CUDA的配置
    OutOfMemoryError 内存溢出问题排查
    springboot 自动注入servlet原理
    ipv6地址概述——带你了解ipv6与ipv4的不同
    视频剪辑技巧:批量剪辑新篇章,AI智剪来领航
  • 原文地址:https://blog.csdn.net/u010321564/article/details/126543396