Python 修改一个对象的值对相关对象的影响

Python 修改一个对象的值对相关对象的影响

python提供了方便的初始化复杂对象的操作,比如使用循环或者*快速构建一个list,而不用一个一个元素手敲进去,但是这样的初始化方式可能带来意想不到的结果。

1.使用*快速构建一个list

list1 = [1, 1, 1]

list2 = [2] * 3
print(list2)
# [2, 2, 2]

print(id(list1[0]), id(list1[1]), id(list1[2]))
# 94726649605440 94726649605440 94726649605440
print(id(list2[0]), id(list2[1]), id(list2[2]))
# 94726649605472 94726649605472 94726649605472

list1[0] = 100
print(list1)
# [100, 1, 1]
list2[0] = 200
print(list2)
# [200, 2, 2]

print(id(list1[0]), id(list1[1]), id(list1[2]))
# 94726649608608 94726649605440 94726649605440
print(id(list2[0]), id(list2[1]), id(list2[2]))
# 94726649611808 94726649605472 94726649605472

id()函数返回对象的内存地址

这里由于python的小整数机制,所有1在内存中只有一个示例,所有2在内存中也只有一个示例,虽然list1和list2的3个元素指向同一块内存,但是修改其中1个的值不会影响到其他2个的值

详解python中的 is 操作符

2.构建一个复杂的list

自定义一个类,将类的对象作为list的元素

class A():
    def __init__(self):
        self.v = 10
        
a = A()
a2 = A()
list3 = [a, a, a]

list4 = [a2] * 3

print(id(list3[0]), id(list3[1]), id(list3[2]))
# 140041873540864 140041873540864 140041873540864

print(id(list4[0]), id(list4[1]), id(list4[2]))
# 140041873540336 140041873540336 140041873540336

list3[0].v = 100
list4[0].v = 200

print(list3[0].v, list3[1].v, list3[2].v)
# 100 100 100
print(list4[0].v, list4[1].v, list4[2].v)
# 200 200 200

print(id(list3[0]), id(list3[1]), id(list3[2]))
# 140041873540864 140041873540864 140041873540864

print(id(list4[0]), id(list4[1]), id(list4[2]))
# 140041873540336 140041873540336 140041873540336

这个时候修改其中1个list的元素就会影响到其它2个元素

3.list中嵌套list(list的元素也是list)

这种情况下内层的list看成是一个复杂对象,如果复杂对象的内存地址相同,那么修改其中一个复杂对象,相关的复杂对象也会变化

list5 = [[5] * 3] * 3
print(list5)
# [
#   [5, 5, 5],
#   [5, 5, 5],
#   [5, 5, 5]
# ]

print(id(list5[0][0]), id(list5[0][1]), id(list5[0][2]))
# 94759677586880 94759677586880 94759677586880

print(id(list5[0]), id(list5[1]), id(list5[2]))
# 139670761854336 139670761854336 139670761854336

list5[1][1] = 50
print(list5)
# [
#   [5, 50, 5], 
#   [5, 50, 5], 
#   [5, 50, 5]
# ]

我们发现当使用*来将一个list按行进行扩展时,从一维扩展到二维

此时我们发现每一行的id值都是相等的,这说明3个行list指向同一块内存,修改其中一个list就会影响到另外2个list。

这里猜测大概是*的关系,将一个list [5,5,5]使用*扩展3份,此时这里的list相当于list4 = [a2] * 3中的a2,也就是其他2个list是使用同一个对象复制的,导致它们几个最后指向同一块内存,修改1个,另外2个也跟着变化。

换一种方式,每次创建list [6,6,6]的时候,都重新初始化

list6 = [[6] * 3 for _ in range(3)]
print(list6)
# [
#   [6, 6, 6],
#   [6, 6, 6],
#   [6, 6, 6]
# ]

print(id(list6[0][0]), id(list6[0][1]), id(list6[0][2]))
# 94759677586912 94759677586912 94759677586912

print(id(list6[0]), id(list6[1]), id(list6[2]))
# 139670761854144 139670761854272 139670761899968

list6[1][1] = 60
print(list6)
# [
#   [6, 6, 6],
#   [6, 60, 6],
#   [6, 6, 6]
# ]

使用这种方式发现3个行list的id是不同的,也就是在内存中分属于不同的区域

python二维列表List修改其中一个数值,所有项数值都改变的问题

当然,手动输入一个3*3的数组肯定也没问题

list7 = [
    [7, 7, 7], 
    [7, 7, 7], 
    [7, 7, 7]
]

print(id(list7[0][0]), id(list7[0][1]), id(list7[0][2]))
# 93963458526720 93963458526720 939634585267202

print(id(list7[0]), id(list7[1]), id(list7[2]))
# 140037817369088 140037816002240 140037816002048

list7[1][1] = 70
print(list7)
# [
#   [7, 7, 7],
#   [7, 70, 7],
#   [7, 7, 7]
# ]

4.个人遇到的问题

构建一个二维的数组(用list表示),然后数组的每个元素也是空的list[]

# 方法1:手动输入
table1 = [
    [ [], [], [] ], 
    [ [], [], [] ], 
    [ [], [], [] ]
]

# 方法2:循环构建
row = [[] for _ in range(3)]
print(row)
# [ [], [], [] ]

table2 = [row for _ in range(3)]
print(table2)

# [
#   [ [], [], [] ], 
#   [ [], [], [] ], 
#   [ [], [], [] ]
# ]

用的方法2构建的table2

检查table1和table2中元素的内存地址

print(id(table1[0][0]), id(table1[0][1]), id(table1[0][2]))
# 140667263779328 140667262412288 140667262458048

print(id(table1[0]), id(table1[1]), id(table1[2]))
# 140667262457984 140667262412224 140667262459008

print(id(table2[0][0]), id(table2[0][1]), id(table2[0][2]))
# 140667262459200 140667262459264 140667262459328

print(id(table2[0]), id(table2[1]), id(table2[2]))
# 140667262459136 140667262459136 140667262459136

print(id(row))
# 140667262459136

可以看到table2的3个行其实是同一块内存,也是是row对象所在的地址,原因在于使用row对象重复构建行

现在尝试对table1和table2的元素进行操作,对下标为[1][1]元素进行数据插入。

data = [1, 2, 3]
table1[1][1].extend(data)
table2[1][1].extend(data)

print(table1)
# [
#   [ [], [], [] ],
#   [ [], [1, 2, 3], [] ],
#   [ [], [], [] ]
# ]

print(table2)
# [
#   [ [], [1, 2, 3], [] ],
#   [ [], [1, 2, 3], [] ],
#   [ [], [1, 2, 3], [] ]
# ]

print(row)
# [ [], [1, 2, 3], [] ]

table1的结果正常

table2整个第2列都被修改了,而且row的值也跟着修改了

所以在创建table的时候不要使用同一个对象复制多份,也就是不要像table2那样多次使用row

使用table3的方式就可以得到正常的结果

table3 = [[[] for i in range(3)] for j in range(3)]
print(table3)
# [
#   [ [], [], [] ],
#   [ [], [], [] ],
#   [ [], [], [] ]
# ]
print(id(table3[0][0]), id(table3[0][1]), id(table3[0][2]))
# 140155553321024 140155553321408 140155553321536

print(id(table3[0]), id(table3[1]), id(table3[2]))
# 140155553321472 140155553321600 140155553321856

table3[1][1].extend(data)
print(table3)
# [
#   [ [], [], [] ],
#   [ [], [1, 2, 3], [] ],
#   [ [], [], [] ]
# ]

5. 补充实验

data = [1, 2, 3]

table4 = [[[] for i in range(3)]] * 3
print(table4)
# [
#   [ [], [], [] ],
#   [ [], [], [] ],
#   [ [], [], [] ]
# ]

print(id(table4[0][0]), id(table4[0][1]), id(table4[0][2]))
# 140360386152064 140360386151552 140360386151616

print(id(table4[0]), id(table4[1]), id(table4[2]))
# 140360386151808 140360386151808 140360386151808

table4[1][1].extend(data)
print(table4)
# [
#   [ [], [1, 2, 3], [] ],
#   [ [], [1, 2, 3], [] ],
#   [ [], [1, 2, 3], [] ]
# ]

这说明*的做法就是对同一个对象多次复制,类似于table2的做法

再次印证*

data=[1,2,3]

table5=[ [] for _ in range(3)]
print(table5)
# [ [], [], [] ]

print(id(table5[0]),id(table5[1]),id(table5[2]))
# 140717454157824 140717454157312 140717454157376

table6=[[]]*3
print(table6)
# [ [], [], [] ]

print(id(table6[0]),id(table6[1]),id(table6[2]))
# 140717454157504 140717454157504 140717454157504

table5[1].extend(data)
print(table5)
# [ [], [1, 2, 3], [] ]

table6[1].extend(data)
print(table6)
# [ [1, 2, 3], [1, 2, 3], [1, 2, 3] ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值