问题之Python的List可变对象

问题之Python的List可变对象,第1张

问题之Python的List可变对象 提示

参考书:《Python疯狂讲义》、兄弟连的《Python基础 编程实战》

1 初识List对象
  • Python 中的 list (列表)基于 PyListObject 实现,列表支持元素的插入、删除、更新 *** 作,因此 PyListObject 是一个变长对象,即列表的长度随着元素的增加(或删除)而变长(或变短);同时它还是一个可变对象,即列表中的元素根据列表的 *** 作而发生变化,内存大小动态的变化
  • 列表(list)其实可以类似于C++、Java的数组。
  • 列表是Python中的对象(object),列表是用来存储对象的对象,对象就是内存中专门用来存储数据的一块区域;
  • 列表中可以保存多个有序的数据,而像数值,它只能保存一个单一的数据;
  • 列表可以通过索引(index)来获取列表中的元素:
    • 索引是元素在列表中的位置,列表中的每一个元素都有一个索引
    • 索引是从0开始的整数,列表第一个位置索引为0,第二个位置索引为1,第三个位置索引为2,以此类推
    • 索引的语法:my_list[索引],如my_list[0]
    • 注意列表索引下标的越界异常:IndexError: list index out of range
  • python 列表的创建:
# 1、创建列表,通过[]来创建(空)列表
my_list = []

# 2、打印该列表,type()为获得my_list的类型
print(my_list , type(my_list))   # 运行结果:[] 

# 列表存储的数据,我们称为元素。一个列表中可以存储多个元素,也可以在创建列表时,来指定列表中的元素。
# 3、创建一个只包含一个元素的列表
my_list = [10] 

# 当向列表中添加多个元素时,多个元素之间使用,隔开
# 4、创建了一个包含有5个元素的列表
my_list = [10,20,30,40,50] 

# 5、列表中可以保存任意的对象,这里可能有点套娃
my_list = [10,'hello',True,None,[1,2,3],['python','java']]

# 6、通过索引获取列表中的元素 
print(my_list[4])  # 运行结果:[1,2,3]

# 7、如果使用的索引超过了最大的范围,会抛出异常
print(my_list[6])  # 运行结果:IndexError: list index out of range

# 8、len()函数,通过该函数可以获取列表的长度,即列表中元素的个数。
# 获取到的长度的值,是列表的最大索引 + 1
print(len(my_list))   # 运行结果:6
2 List 引用传递后的改变
# list(列表)
a = [1,2,3]
b = a
b[0] = 2     # 由于list是可变对象,改变b的时候会导致a的改变,列表a和b都是[2,2,3]
print(a)
print(b)

'''
运行结果:
[2,2,3]
[2,2,3]
'''

# str(字符串)
s = 'abc'
s2 = s
s2 += 'd'   # 由于str是不可变对象,s2是新建的对象,s2的修改不会影响s。s为'abc',s2为'abcd'。
print(s)
print(s2)
'''
运行结果:
'abc'
'abcd'
'''
3 List 的坑

建议不要花里胡哨

a = [1,2,3]
b = a
a is b      # 运行结果:True
# 因为按引用传递,a和b存的地址(引用)是一样的,改变b相当于改变a。

b = a[:]
a is b       # 运行结果:False
# 想使用list的值却不想修改原list时可以使用切片[:]拷贝一份到新空间。

a = [1,2,3]
id(a)    # 运行结果:140376329323528
a = [1,2,3]
id(a)    # 运行结果:140376359286920
# 两次定义相同的list,但是其地址并不相同,会创造新对象

a = [1,2,3]
id(a)    # 运行结果:140376329323528
a[:] = [1,2,3]
id(a)    # 运行结果:140376329323528
# 因为a[:]切片创建的是新空间,对新空间赋值不影响旧空间a,所以a的地址跟原来一致。

a =[ [0]*2 ]* 2   # 用这种方式创建一个二维list,此时a为[[0,0],[0,0]]。(容易出现坑)
a[0] is a[1]      # True,这种创建方法的机制是复制list,所以2个list其实是同一个list。
a[0][0] = 1       # 改变第一个list时,第二个list也改变,此时a为[[1,0],[1,0]]。
a[0] += [1]       # 改变第一个list时,第二个list也改变,此时a为[[1,0,1],[1,0,1]]。+=相当于extend,对list进行原地修改。

a[0] = a[0] + [1] # 改变第一个list时,第二个list不改变,此时a为[[1,0,1,1],[1,0,1]]。因为不是原地改变,而是创建了新list,然后给原来的引用赋了新值。
a[0] = [1,2]      # a[0]指向创建的新list[1,2]。此时a[1]不变,a为[[1,2],[1,0,1]]。同样是给a[0]赋值了新的list[1,2],不会影响到a[1]。

a = [[0]*2 for _ in range(2)] # 相对正确的创建方式,这样创建的二维list,改变a[0]并不会影响a[1]
a[0] is a[1]                 # 运行结果:False
a = [ []*1000 ]          # 同理,运行结果:[]。并不能得到含有1000个空list的list。(容易出现坑)
a = [ [] for _ in range(1000) ]  # 正确的定义方式

x = float('han')
x == x, [x] == [x] # 运行结果:False, True 
# 因为list之间比较的时候先比较元素的地址,如果相等则认为相等,当id不相等

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/870389.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-13
下一篇 2022-05-13

发表评论

登录后才能评论

评论列表(0条)

保存