Python 6-1.内置数据结构之list(基础篇)


-常见内置数据结构-
list 列表
set 集合
dict 字典
tuple 元祖
-本章大纲-
  • list(列表):
    一组由顺序的数据的组合
    创建列表
    有值列表
    无值列表(空列表)
    使用list创建列表
    修改列表值
    列表常用操作
    访问列表
    使用下标操作(索引),大部分语言索引都是从0开始
    列表位置从0开始
    语法: list[val]
    分片操作(截取操作)
    从列表里截取任意一段
    语法: list[开始:结束]
    del(删除命令)
    列表的连接
    使用乘加来对列表操作
    列表成员资格运算
    列表的遍历使用
    使用for和while来遍历,对比过程
    双层列表循环
    列表内涵:list content
    关于列表的常用函数
    len(list)获取列表长度
    mxn(list)求列表最大值
    min(list)求列表最小值
    list(str)把字符串拆分成字符并存入列表里面
    list.append(val)在列表尾部追加内容
    list.insert(index,val)在指定下标前面插入内容
    list.pop(index) 取出指定下标的值
    list.remove(index.max)删除指定下标的内容
    list.clear()清空列表里面的内容
    list.reverse()f翻转列表类容,原地翻转地址不变
    list.extend(list2)拓展列表,把一个列表拼接到另一个后面
    list.count()查找列表中相同指定值或元素的数量
    list.copy()浅拷贝
    copy.deepcopy(list)深拷贝
     

 



空列表案例

 

l1 = []
print(type(l1))
print(l1)

 

结果如下:
<class 'list'>
[]

 


带值列表案例
l2 = ["1","2","lalla","啦啦啦"]
print(type(l2))
print(l2)

 

结果如下:
<class 'list'>
['1', '2', 'lalla', '啦啦啦']

 



使用list()来创建空列表
l3 = list()
print(type(l3))
print(l3)

 

结果如下:
<class 'list'>
[]

修改列表内容
l = [1,2,3,4,5]
print(l)# 修改前
l[1] = 100
print(l[:])# 修改后 

 

结果如下:
[1, 2, 3, 4, 5]
[1, 100, 3, 4, 5]

 



修改一部分列表的内容
l = [1,2,3,4,5]
print(l)# 修改前
l[1:3] = 100,200
print(l)# 修改后

结果如下:
[1, 2, 3, 4, 5]
[1, 100, 200, 4, 5]

 

 



-列表常用操作-
访问列表
使用下标操作(索引),大部分语言索引都是从0开始
列表位置从0开始
语法: list[val]
分片操作(截取操作)
从列表里截取任意一段
语法: list[开始:结束]
del(删除命令)
列表的连接
使用乘加来对列表操作
列表成员资格运算
列表的遍历使用
使用for和while来遍历,对比过程
双层列表循环
列表内涵:list content
关于列表的常用函数


下标访问列表案例
l = [1,2,4,123,3]
print(l[3]) #下标从0开始,所以截取的下标3为第四个

 


结果如下:
123

-分片操作-
  • 注意截取范围,一般来说有开始和结束两个下标值都是包括左不包括右
 案例如下
l = [1,2,4,123,3]
print(l[1:4])  #截取从第二个到第四个

 

结果如下:
[2, 4, 123]

 


下标值可以为空,如果不屑,左边下标值默认为0,右边下标值默认为最大数加一,也就是说截取到最后一位
注意最终打印的结果

左右下标完全不写
l = [1,2,4,123,3]

print(l[:])

 

结果如下:
[1, 2, 4, 123, 3]

 


只写左边下标
l = [1,2,4,123,3]

print(l[1:])

 

结果如下:
[2, 4, 123, 3]

 


只写右边下标
l = [1,2,4,123,3]

print(l[:4])

 

结果如下:
[1, 2, 4, 123]

 


分片操作可以控制增长幅度,默认增长幅度为1
l = [1,2,4,123,3]

print(l[1:6:1])

 

结果如下:
[2, 4, 123, 3]

 


打印从下标1到4的数字,每次遍历中间隔开一个
l = [1,2,4,123,3]

print(l[1:4:2])

 

结果如下:
[2, 123]

 


下标索引可以超出范围,不过超出后不会提示错误并且不考虑多余下标内容
l = [1,2,4,123,3]

print(l[1:100])

 

结果如下:
[2, 4, 123, 3]

 


-下标值和增长幅度可以为负数-
  • 当下标值为负数时,索引遍历的顺序就会相反,即从右到左
  • 当下标值为负数时,列表里最后的内容下标为-1


分片操作 下标值为负,案例如下

无论下标值是否为负,左边的下标值一定要比右边的下标值小
l = [1,2,4,123,3]

print(l[-2:-4])  #执行结果为空
print(l[-4:-2])

 

结果如下:
[]
[2, 4]

 


如果分片的左边下标值一定要比右边下标值大,则增长幅度要使用负数
此案例为一个list直接正反颠覆提供了一种思路
l = [1,2,4,123,3]

print(l[-2:-4:-1])

 

结果如下:
[123, 4]

 



-分片操作是生成一个新的list-
  • 内置函数id,负责显示一个遍历或数据的唯一确定编码

 

      id函数案例如下

a = 100
b = 200


     两个变量不能通过值来对其身份判断

     可以通过id函数获取编码进行对比

 

print(id(a))
print(id(b))
结果如下:
140723906273408
140723906276608

 

 

     我们对比c和b的编码,可以看出c和b并不是同一身份,而a和c确实统一身份,这就涉及到传值和传址

 

c = a
print(id(c))
结果如下:

 

140723906273408

 

     

这里更改了a的值,按照逻辑,c的值也应该更改,但是我们看编码,c的值并没有发生变化,这就是顺序结构的影响,c所接收的值是还没更改的a的值,再a更改过后,c并未接收到指令需要再次更改

 

a = 101
print(id(a))
print(id(c)) 
结果如下:
140723906273440
140723906273408

 


     当c再次接收指令需要更改值时的编码

 

c = a
print(id(a))
print(id(c))
print(id(a)==id(c)) #返回的结果为true

 

结果如下:
140723906273440
140723906273440
True

 



     使用id内置函数来判断截取的list是否是新生成的列表

 

l = [3,2,1,23,3]
ll = l[:] #通过截取方式赋值
lll = l #直接进行赋值

 


     对比三者的编码

print(id(l))
print(id(ll))
print(id(lll)) #很明显,直接赋值的编码跟原来的list完全一致

 

结果如下:
1425021100616
1425021100680
1425021100616

 



     我们再次通过修改列表的内容,来证实

l[1] = 100
print(l)
print(ll)
print(lll)

 

结果如下:
[3, 100, 1, 23, 3]
[3, 2, 1, 23, 3]
[3, 100, 1, 23, 3]

 


     通过结果可以看出截取的list并未发生任何变化,反之直接赋值的list就跟原本list发生了相同的变化,这又是传值和传址的问题




-del 删除命令-
  • 语法:
  • del 列表名称[需要删除内容的下标]

 

    删除案例如下:

a = [1,2,3,4,5]
del a[2]
print(a)

 

结果如下:
[1, 2, 4, 5]

利用id内置函数查看删除过后的list是否还是原来的列表,还是系统给重新生成了一个
a = [1,2,3,4,5]
print(id(a))  # 删除前
del a[2]
print(id(a))  # 删除后

 

结果如下:
1617250837064
1617250837064

 


从id给的编码看得出来,并没有不同,证明删除的内容是直接从list里删除,而不是将不需要删除的内容重新放置到一个新的list里面

del删除了一个变量之后不能再继续使用该变量

 

a = [1,2,3,4,5]
del a
print(a) #删除列表类型的变量

b = 1
del b
print(b) #删除普通变量

 

结果如下:
Traceback (most recent call last):
  File "D:/图灵/2.基础语法/测试.py", line 3, in <module>
    print(a) #删除列表类型的变量
NameError: name 'a' is not defined

 


无论删除任何类型的变量,后面都不能再继续使用该变量



-列表的连接使用-
  • 使用算术运算符进行链接

使用加号连接两个列表
a = [1,2,3,4,5]
b = [6,7,8,9,10]
c = a + b
print(c)

结果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 


使用乘号操作列表
a = [1,2,3,4,5]
b = a * 3
print(b)

 

结果如下:
[1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

 


得到的值相当于n和相同的列表相加

列表成员资格运算
  • 使用in成员运算符进行操作(关于in函数前面"表达式章节有讲")

 

使用in进行操作

a = [1,2,3,4,5]
b = 8
print(b in a) #返回值为布尔值
结果如下:
False

 


使用not in进行操作
a = [1,2,3,4,5]
b = 8
print(b not in a)

结果如下:
True

 

 




-列表的遍历-
  • for
  • while(凡是关于遍历的大都不推荐)

使用for进行遍历操作
案例如下
a = [1,2,3,4,5]
for i in a:
    print(i) #通过遍历打印
     #对比两种打印之后值的类型
    print(type(i))
print(a) #直接打印
print(type(a))

 

结果如下:
1
<class 'int'>
2
<class 'int'>
3
<class 'int'>
4
<class 'int'>
5
<class 'int'>
[1, 2, 3, 4, 5]
<class 'list'>

 


通过遍历打印和直接打印的最大区别是,前者把整个列表拆散,一个一个去访问里面的值然后进行打印,后者直接看作一个整体进行打印
我们可以看到遍历打印之后的值是int类型,而直接遍历的值为list类,看得出来拆分过后的值类型是按照原本它在列表时的类型进行输出


有个很有意思的东西,分享给大家,这是大拿老师分享给我们的
不常写python代码的程序员写的python代码是这样的
a = [1,2,3,4,5]
for i in range(0,len(a)): #他们会把a(列表)看成一个值,把列表的内容获取之后存入range再通过for进行打印
    print(a[i])
    i += 1

 

 


使用while循环访问list(麻烦死了=-=)
不推荐使用while遍历list

len(list,tuple,dict)=返回对象(字符、列表、元组等)长度或项目个数
a = [1,2,3,4,5]
 #定义index表示list的下标
index = 0
while index < len(a):
    print(type(a[index]))
    print(a[index]) #将第index个a进行打印
    index += 1 #让下标每遍历一次就进行下一个下标的遍历

 


结果如下:
<class 'int'>
1
<class 'int'>
2
<class 'int'>
3
<class 'int'>
4
<class 'int'>
5

 



-双层列表循环-
a = [["zhansan",12,"游戏"],["lisi",13,"游泳"],["wangwu",15,"篮球"]]

 


打印方法:每个列表有多少个值就用多少个变量进行带出
for k,v,w in a:
    print(k,"--",v,"--",w)
结果如下:
zhansan -- 12 -- 游戏
lisi -- 13 -- 游泳
wangwu -- 15 -- 篮球

 


循环变量的个数应该于列表解包出来的变量个数一致
a = [["zhansan",12,"游戏"],["lisi",13,"游泳"],["wangwu",15,"篮球",1,2,3,4,]]

  打印方法:每个列表有多少个值就用多少个变量进行带出,否则就会出错
for k,v,w in a:
     print(k,"--",v,"--",w)

 

结果如下:
Traceback (most recent call last):
zhansan -- 12 -- 游戏
lisi -- 13 -- 游泳
  File "D:/图灵/2.基础语法/测试.py", line 2, in <module>
    for k,v,w in a:
ValueError: too many values to unpack (expected 3)

 





-列表内涵:list content-
  • 通过简单方法创作列表

通过for遍历出来的值放置到一个新的列表里面来形成一个列表
a = [1,2,3,4]
 #通过list a 来创建新的list b
b = [i for i in a]
print(a)
print(b)
 #对比id编码是否相等
print(id(a))
print(id(b))

 

结果如下:
[1, 2, 3, 4]
[1, 2, 3, 4]
1651187802696
1651187802760

 


通过代码我们可以看出就算b列表的值是从a列表里面获得的,但是编码显示它们不是同一个变量


在生成新的列表时,使用乘号对列表值进行操作
案例条件:让b里面的所有值乘以10
a = [1,2,3,4,5]
b = [i*10 for i in a]
print(a)
print(b)
结果如下:
[1, 2, 3, 4, 5]
[10, 20, 30, 40, 50]

 



还可以通过算法将过滤的内容放置新列表
使用for i in range生成从1到34的列表a,将列表a里面的偶数生成一个列表b
a = [i for i in range(1,34)]
b = [r for r in a if r%2 == 0]
print(a)
print(b)

 


结果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32]

 


列表生成式可以嵌套
a = [i for i in range(1,5)] #生成 list a
b = [i for i in range(100,500) if i % 100 == 0]

 


 


将a和b列表里面的值对应相加并且放置新列表c里面
n将a列表内容逐个遍历,m将b列表内容逐个遍历
c = [n+m for n in a for m in b]
 #分别打印a,b,c列表对比内容
print(a)
print(b)
print(c)

 

结果如下:
[1, 2, 3, 4]
[100, 200, 300, 400]
[101, 201, 301, 401, 102, 202, 302, 402, 103, 203, 303, 403, 104, 204, 304, 404]


将c里面的表达式详细版:案例如下
其实就是个嵌套循环
for n in a:
    for m in b:
        print(m+n,end=" ") #end是print内置函数的一个参数,规定空格,默认值end="\n"

help(print) #查看print的官方帮助文档,help(函数名) = 查看该函数的官方帮助文档

 

结果如下:
101 201 301 401 102 202 302 402 103 203 303 403 104 204 304 404 
Help on built-in function print in module builtins:

print(...)
    print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
    
    Prints the values to a stream, or to sys.stdout by default.
    Optional keyword arguments:
    file:  a file-like object (stream); defaults to the current sys.stdout.
    sep:   string inserted between values, default a space.
    end:   string appended after the last value, default a newline.
    flush: whether to forcibly flush the stream.

 





-列表的常用函数-
  •                          len(list)获取列表长度
  •                         mxn(list)求列表最大值
  •                         min(list)求列表最小值
  •                         list(str)把字符串拆分成字符并存入列表里面
  •                         list.append(val)在列表尾部追加内容
  •                         list.insert(index,val)在指定下标前面插入内容
  •                         list.pop(index) 取出指定下标的值
  •                         list.remove(index.max)删除指定下标的内容
  •                         list.clear()清空列表里面的内容
  •                         list.reverse()f翻转列表类容,原地翻转地址不变
  •                         list.extend(list2)拓展列表,把一个列表拼接到另一个后面
  •                         list.count()查找列表中相同指定值或元素的数量
  •                         list.copy()浅拷贝
  •                         copy.deepcopy(list)深拷贝


求列表长度
len(list)获取列表长度
a = [x for x in range(1,100)]
print(len(a))

 

结果如下:
99

求列表中最大值
mxn(list)求列表最大值
a = [x for x in range(1,100)]
print(max(a))

 

结果如下:
99

求列表中最小值
min(list)求列表最小值
a = [x for x in range(1,100)]
print(min(a))

 

结果如下:
1

如果获取列表最大值的类型为str,则选择字符最长的为最大值
a = ["a","ab","abc"]
print(max(a))
# min同理
print(min(a))

 

结果如下:
abc
a

 


list(str)把字符串拆分成字符并存入列表里面
s = "Baby, there's nothing holding me back"
print(list(s))

 


结果如下:
['B', 'a', 'b', 'y', ',', ' ', 't', 'h', 'e', 'r', 'e', "'", 's', ' ', 'n', 'o', 't', 'h', 'i', 'n', 'g', ' ', 'h', 'o', 'l', 'd', 'i', 'n', 'g', ' ', 'm', 'e', ' ', 'b', 'a', 'c', 'k']

 


把range产生的内容转化成list
list(range(start,stop))
print(list(range(1,10)))
结果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9]

 

 

list.append(val)在列表尾部追加内容
a = [i for i in range(1,10)]
print(a) #追加前
a.append(100)
print(a) #追加后

 

 

结果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 100]

 

 

list.insert(index,val)在指定下标前面插入内容
a = [i for i in range(1,10)]
print(a)
a.insert(3,100) #在下标为3的前面插入一个内容
print(a)

 


结果如下:

[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 100, 4, 5, 6, 7, 8, 9]

 

 删除
  • del 和 pop的区别,前者为直接删除,后者为取出
del删除,直接在列表里面删除
a = [i for i in range(1,10)]
print(a)
del a
print(a) #删除之后无法调用

 

结果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Traceback (most recent call last):
  File "D:/图灵/2.基础语法/测试.py", line 4, in <module>
    print(a) #删除之后无法调用
NameError: name 'a' is not defined

 



pop则是从对应的下标位置取出一个元素,取出的元素为最后一个
a = [i for i in range(1,10)]
print(a.pop())

 

结果如下:
9

  

list.remove(index.max)删除指定下标的内容
  • 如果被指定要删除的值没在list中,则会报错
  • 所以在使用remove时,最好使用先行判断

 

 查看remove操作时直接从列表里面进行删除,还是将值取出来放置到一个新的list里面
a = [i for i in range(1,10)]
print(id(a))# 删除前
aa = 8 #指定一个值
if aa in a:
    a.remove(aa)
print(a)
print(id(a))# 删除后

 


 

结果如下:
2721021846088
[1, 2, 3, 4, 5, 6, 7, 9]
2721021846088

 


list.clear()清空列表里面的内容
 使用clear来清空,我们可以看到列表还在,而且里面的地址也是一致的
a = [i for i in range(1,10)]
print(a)
print(id(a))
a.clear()
print(a)
print(id(a))

 

结果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
2428798329416
[]
2428798329416

 


如果不计较地址问题时,我们可以直接使用空的list去替换掉,但这时地址就不一致了
a = []
print(a)
print(id(a))

 

结果如下:
[]
2158892847240

 

 

 list.reverse()f翻转列表类容,原地翻转地址不变
a = [1,2,3,4,5]
print(a)# 翻转前
print(id(a))
a.reverse()
print(a)# 翻转后
print(id(a))# 翻转过后还是同一个列表
结果如下:

[1, 2, 3, 4, 5]
2783136211528
[5, 4, 3, 2, 1]
2783136211528

 


list.extend(list2)拓展列表,把一个列表拼接到另一个后
a = [1,2,3,4]
b = [6,7,8,9,10]
print(a) #拼接前
print(id(a))
a.extend(b)
print(a)# 拼接后
print(id(a))
print(a+b) #使用拼接手法来拓展列表,能使拓展列表原来的地址保存,而直接相加来拓展,则会生成一个新的列表
print(id(a+b))
结果如下:
[1, 2, 3, 4]
2219187266120
[1, 2, 3, 4, 6, 7, 8, 9, 10]
2219187266120
[1, 2, 3, 4, 6, 7, 8, 9, 10, 6, 7, 8, 9, 10]
2219216318920

 

 

list.count()查找列表中相同指定值或元素的数量
a = [1,2,3,3,4,2]
print(a)
print(a.count(2)) #列表中有两个2

 

结果如下:
[1, 2, 3, 3, 4, 2]
2

 

 



copy:拷贝,此函数是浅拷贝

关于拷贝和直接赋值的区别
直接赋值案例:
a = [1,2,3,4,5]
b = a
print(id(a))
print(id(b))

 

结果如下:
1296231391816
1296231391816

 


直接赋值的id是一致的,那就是说无论在何处修改修改a或b另一个都会发生改变
b[3] = 111
print(a)
print(b)

 

结果如下:
[1, 2, 3, 111, 5]
[1, 2, 3, 111, 5]

 



拷贝案例
a = [1,2,3,4,5]
b = a.copy()
print(id(a))
print(id(b))

 

结果如下:
1312161292872
1312161292936

 


通过a拷贝的b列表里面的id与a列表完全不符合,这就可以在修改a或b时不会影响到另一个列表了
a[1] = 888
print(a)
print(b)
结果如下:
[1, 888, 3, 4, 5]
[1, 2, 3, 4, 5]

 


浅拷贝和深拷贝的区别
copy函数只是个浅拷贝函数,只拷贝一层内容
a = [1,2,3,[1,2,3,4]]
b = a.copy()
print(id(a))
print(id(b))

 

结果如下:
2354867757704
2354868916552

 


这时使用id函数访问a列表里面的双层列表
print(id(a[3]))
print(id(b[3]))

 

结果如下:
2869806391880
2869806391880

 


由此可见,浅拷贝无法拷贝双层列表里面的内容

我们通过修改来查看区别
修改双层列表内容
a[3][2] = 636
print(a)
print(b)

 

结果如下:
[1, 2, 3, [1, 2, 636, 4]]
[1, 2, 3, [1, 2, 636, 4]]

 


修改列表内容
a[3][2] = 111
print(a)
print(b)

 

结果如下:
[1, 2, 3, [1, 2, 111, 4]]
[1, 2, 3, [1, 2, 111, 4]]

 


只有双层列表里面的内容可以被修改

使用深拷贝来拷贝双层列表
引入copy库
import copy
a = [1,2,3,[1,2,3,4]]
b = copy.deepcopy(a)
print(a)
print(id(a))
print(b)
print(id(b))

 

结果如下:
[1, 2, 3, [1, 2, 3, 4]]
2427933269384
[1, 2, 3, [1, 2, 3, 4]]
2427933267848

 


再查看双层列表的id
print(id(a[3]))
print(id(b[3]))

 

结果如下:
1724958056840
1724958057160

 


这时双层列表内容的id也发生了变化
通过改变a双层列表里面的内容来观察变化
a[3][2] = 666
print(a)
print(b)

 

结果如下:
[1, 2, 3, [1, 2, 666, 4]]
[1, 2, 3, [1, 2, 3, 4]]

 


这时b列表的双层列表并没有发生变化,这就是浅拷贝和深拷贝的区别



关于传值和传址的区别
def int(n):
    n += 100
    print(id(n))
    print(n)


def list(n):
    n[2] = 100
    print(id(n))
    print(n)
    return None


n1 = 1
n2 = [1, 2, 3, 4, 5]

print(n1)
print(id(n1))
int(n1)
print(n1)
print(id(n1))

print(n2)
print(id(n2))
list(n2)
print(n2)
print(id(n2))

 

我们观察在调用函数前和调用函数后,int和list类型的两个变量编码的变化

 

结果如下:

1
140723906270240
140723906273440
101
1
140723906270240
[1, 2, 3, 4, 5]
2431234302536
2431234302536
[1, 2, 100, 4, 5]
[1, 2, 100, 4, 5]
2431234302536

 


我们可以看到两个函数,经过函数改变之后,函数局部打印和全局打印列表是一致的,反之int方面则不同
因为对于列表来说传入的参数为传址,所以在全局打印时访问的地址和局部的相同,则打印的内容也相同
而int传入的参数为传值,因为局部访问时访问的是参数的值,当全局访问时无法获得经过函数改之后参数的值,所以值没发生改变

文笔不好,仅供参考


要有错误或者有其他更多的见解,欢迎大家加我QQ384435742来交流


想第一时间看更新的文章,请关注,谢谢




posted on 2018-09-23 22:28  阎冬  阅读(759)  评论(0编辑  收藏  举报

导航