鱼C论坛

 找回密码
 立即注册
查看: 1666|回复: 19

[已解决]关于列表切片的疑问?

[复制链接]
发表于 2018-2-24 15:38:24 | 显示全部楼层 |阅读模式
100鱼币
本帖最后由 哭吧叫吧 于 2018-2-24 16:12 编辑
  1. #创建一个用于存储外星人的空列表
  2. aliens=[]
  3. #创建30个绿色外星人
  4. for alien_number in range(30):
  5.         new_alien={"color":"green","point":5,"speed":"slow"}
  6.         aliens.append(new_alien)
  7. #修改前三个
  8. for alien in aliens[0:3]:
  9.         if alien["color"]=="green":
  10.                 alien["color"]="yellow"
  11.                 alien["speed"]="medium"
  12.                 alien["point"]=10
  13. #显示前5个外星人
  14. for alien in aliens[0:5]:
  15.         print(alien)
复制代码



结果显示 修改成功:
  1. {'color': 'yellow', 'point': 10, 'speed': 'medium'}
  2. {'color': 'yellow', 'point': 10, 'speed': 'medium'}
  3. {'color': 'yellow', 'point': 10, 'speed': 'medium'}
  4. {'color': 'green', 'point': 5, 'speed': 'slow'}
  5. {'color': 'green', 'point': 5, 'speed': 'slow'}
复制代码



问题来了,众所周知,列表切片产生的是列表的副本,与原列表不是同一份空间。如:

  1. #修改列表前三项为字符“11111111”
  2. for alien in aliens[0:3]:
  3.         alien="111111111111"
复制代码

结果显示 修改不成功:
  1. {'color': 'green', 'point': 5, 'speed': 'slow'}
  2. {'color': 'green', 'point': 5, 'speed': 'slow'}
  3. {'color': 'green', 'point': 5, 'speed': 'slow'}
  4. {'color': 'green', 'point': 5, 'speed': 'slow'}
  5. {'color': 'green', 'point': 5, 'speed': 'slow'}
复制代码



但是!!!在外星人代码里,修改了列表切片为什么会对原版会有影响,而我自己改成“1111111111”对原版完全没有影响????


最佳答案
2018-2-24 15:38:25
本帖最后由 运运520 于 2018-2-24 17:08 编辑
哭吧叫吧 发表于 2018-2-24 17:02
照你的说法,这个代码应该能做到改原本列表内元素的值。但结果还是不行。


你那个代码还是直接修改的列表啊,拿元组来解释,元组是不是不可以变,那元组里面的字典可不可以变?

dict1 = {'hero': 'yourself'}
tuple1 = (dict1, 2, 3)
print(tuple1)
tuple1[0]['hero'] = 'myself'
print(tuple1)
你执行一次。。。。
({'hero': 'yourself'}, 2, 3)
({'hero': 'myself'}, 2, 3)

那个你说的例子里面他改的不是列表,是改的列表里面的字典,无论切不切片,字典的内存地址是没变的。。。修改字典里面的数据跟元组没有任何关系了,每段代码都会在编译器里面占有一段内存地址,字典是实例化的字典类,地址不会变。。。

最佳答案

查看完整内容

你那个代码还是直接修改的列表啊,拿元组来解释,元组是不是不可以变,那元组里面的字典可不可以变? dict1 = {'hero': 'yourself'} tuple1 = (dict1, 2, 3) print(tuple1) tuple1[0]['hero'] = 'myself' print(tuple1) 你执行一次。。。。 ({'hero': 'yourself'}, 2, 3) ({'hero': 'myself'}, 2, 3) 那个你说的例子里面他改的不是列表,是改的列表里面的字典,无论切不切片,字典的内存地址是没变的。。。修改字 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 15:38:25 | 显示全部楼层    本楼为最佳答案   
本帖最后由 运运520 于 2018-2-24 17:08 编辑
哭吧叫吧 发表于 2018-2-24 17:02
照你的说法,这个代码应该能做到改原本列表内元素的值。但结果还是不行。


你那个代码还是直接修改的列表啊,拿元组来解释,元组是不是不可以变,那元组里面的字典可不可以变?

dict1 = {'hero': 'yourself'}
tuple1 = (dict1, 2, 3)
print(tuple1)
tuple1[0]['hero'] = 'myself'
print(tuple1)
你执行一次。。。。
({'hero': 'yourself'}, 2, 3)
({'hero': 'myself'}, 2, 3)

那个你说的例子里面他改的不是列表,是改的列表里面的字典,无论切不切片,字典的内存地址是没变的。。。修改字典里面的数据跟元组没有任何关系了,每段代码都会在编译器里面占有一段内存地址,字典是实例化的字典类,地址不会变。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 15:58:27 | 显示全部楼层
alien="111111111111"  你的这个好像是个局部变量影响不了全局变量的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 16:03:42 | 显示全部楼层
你修改的就是列表本身,那切片就是做遍历用的
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-2-24 16:04:19 | 显示全部楼层
南城顾她 发表于 2018-2-24 15:58
alien="111111111111"  你的这个好像是个局部变量影响不了全局变量的
  1. for alien in aliens[0:3]:
  2.         if alien["color"]=="green":
  3.                 alien["color"]="yellow"
  4.                 alien["speed"]="medium"
  5.                 alien["point"]=10
复制代码


为什么他这个可以!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-2-24 16:08:44 | 显示全部楼层
alltolove 发表于 2018-2-24 16:03
你修改的就是列表本身,那切片就是做遍历用的

他遍历切片,修改列表内元素内容。我也是遍历切片,修改元素内容,我怎么就不行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 16:22:14 | 显示全部楼层
哭吧叫吧 发表于 2018-2-24 16:08
他遍历切片,修改列表内元素内容。我也是遍历切片,修改元素内容,我怎么就不行

哦,你这个是修改切片的元素了,你那个切片就相当于是原来你列表的副本,你的原来列表不受影响
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-2-24 16:25:56 | 显示全部楼层
alltolove 发表于 2018-2-24 16:22
哦,你这个是修改切片的元素了,你那个切片就相当于是原来你列表的副本,你的原来列表不受影响

我也是这么觉得,但是什么他就行,就因为列表内元素为dict,然后修改dict[key],就能修改原版列表?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 16:32:47 | 显示全部楼层
那就是说整个数组的切片是副本,但是每一个元素确是引用原来数组的元素,也有可能
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 16:34:03 | 显示全部楼层
同理,为什么a[:1] 能改变列表a的值
>>> a = [1,2,3]
>>> a[:1] = [3,3]
>>>a
[3,3,2,3]
>>> a[0] = [3,3]
>>> a
[[3, 3], 3, 2, 3]
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 16:38:19 | 显示全部楼层
哭吧叫吧 发表于 2018-2-24 16:04
为什么他这个可以!

我理解的alien="111111111111"  不能更改的原因是alien是一个字典,字典是不可更改的。而alien['color']='yellow' 实则是在改列表的值
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-2-24 16:40:48 | 显示全部楼层
bozhen 发表于 2018-2-24 16:34
同理,为什么a[:1] 能改变列表a的值
>>> a = [1,2,3]
>>> a[:1] = [3,3]
  1. aliens=[]
  2. for alien_number in range(30):
  3.         new_alien={"color":"green","point":5,"speed":"slow"}
  4.         aliens.append(new_alien)

  5. for alien in aliens[0:3]:
  6.         if alien={}

  7. print(aliens)

复制代码


结果还是没变
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 16:48:59 | 显示全部楼层
。。。。。大兄弟。他修改的是字典。。你修改的是列表。。。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-2-24 16:53:13 | 显示全部楼层
运运520 发表于 2018-2-24 16:48
。。。。。大兄弟。他修改的是字典。。你修改的是列表。。。

我和他都是修改的是切片
  1. aliens[0:3]
复制代码
,按理说切片本质都是副本,不应该影响原版的。但是他通过dict[index]的格式,从切片副本修改了原版列表。我觉得很不合理。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 16:57:18 | 显示全部楼层
。。。切片是切的列表,列表里面关于字典的内存地址没变,意味着副本里面的字典指向跟列表里面是一样的,那你修改了这个地方的字典的元素,原列表为什么不可以改变?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2018-2-24 17:02:12 | 显示全部楼层
运运520 发表于 2018-2-24 16:57
。。。切片是切的列表,列表里面关于字典的内存地址没变,意味着副本里面的字典指向跟列表里面是一样的,那 ...
  1. aliens=[]
  2. for alien_number in range(30):
  3.         new_alien={"color":"green","point":5,"speed":"slow"}
  4.         aliens.append(new_alien)

  5. for alien in aliens[0:3]:
  6.         alien={}

  7. print(aliens)
复制代码

照你的说法,这个代码应该能做到改原本列表内元素的值。但结果还是不行。


要改成
  1. for alien in aliens[0:3]:
  2.         alien.clear()
复制代码

就能修改原本列表中前三项字典,并把他们改成{}

alien={} 和 alien.clear() 从语法上看是一样的,但是结果完全不一样。一个有效果,一个完全没效果。真是怪!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 17:09:11 | 显示全部楼层
做个有意思的实验:
  1. li = [{0:0},{1:1},{2:2},{3:3}]
  2. for i in li[0:3]:
  3.         print(i)
  4.         i[0] = '*'
  5.         print(li)
复制代码

结果:
  1. {0: 0}
  2. [{0: '*'}, {1: 1}, {2: 2}, {3: 3}]
  3. {1: 1}
  4. [{0: '*'}, {1: 1, 0: '*'}, {2: 2}, {3: 3}]
  5. {2: 2}
  6. [{0: '*'}, {1: 1, 0: '*'}, {2: 2, 0: '*'}, {3: 3}]
复制代码

有点意思哈~:
  1. li = [{0:0},{1:1},{2:2},{3:3}]
  2. for i in li[0:3]:
  3.         #print(i)
  4.         i[0] = '*'
  5.         print(id(i))
  6.         #print(li)
  7. print('==========我是分割线=========')
  8. print(id(li[0]))
  9. print(id(li[1]))
  10. print(id(li[2]))
复制代码

结果:
  1. 2142288438760
  2. 2142288976488
  3. 2142288976632
  4. ==========我是分割线=========
  5. 2142288438760
  6. 2142288976488
  7. 2142288976632
复制代码

所以可以看的出来在含有字典的列表中我们遍历切片的同时可以修改内部的字典元素
这有点像是修改元组的赶脚
  1. >>> a = ({0:1},1)
  2. >>> a
  3. ({0: 1}, 1)
  4. >>> a[0][0]=2
  5. >>> a
  6. ({0: 2}, 1)
复制代码

评分

参与人数 1鱼币 +5 收起 理由
哭吧叫吧 + 5 感谢回答!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 17:58:25 | 显示全部楼层
LZ你这么理解
就是字典是不可变值,它的内存地址分配以后不能改变
当你修改它里面的key对应的value是可以的,但是当你想直接吧一个新的对象赋值给它的时候它是拒绝的
clear可以是因为它并不是改变了对象的指向,而只是把里面的值清除了
可以看源码里面的提示
def clear(self): # real signature unknown; restored from __doc__
        """ D.clear() -> None.  Remove all items from D. """
        pass

评分

参与人数 1鱼币 +5 收起 理由
哭吧叫吧 + 5 是!这问题本质还是 可变值 和 不可变值的.

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 18:49:43 | 显示全部楼层
for alien in aliens[:3]中的切片,alien是指向原来的aliens,并没有生成新的列表
alien是指向全局变量的一个字典,使用alien['color']是修改这个字典,所以全局变量就改变了
但是如果使用alien = “asdf”,alien就指向了“asdf”这样的空间
如:
dic = {“name”:123}
dic["name"] = 222 修改字典
dic = "123" 指向了另一块空间
dic["name"] = 13 这将会抛出异常,因为dic已经指向了一个字符串,并不是一个字典

评分

参与人数 1荣誉 +5 收起 理由
哭吧叫吧 + 5 感谢回答!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-2-24 19:26:00 | 显示全部楼层
看图片,其实类似于C语言里面的指针。小甲鱼的书里面就有类似的图,比较容易让人理解。 alien.png

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-26 15:28

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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