如何理解这一句 Python 的赋值语句?

2016-08-22 19:56:18 +08:00
 jmyz0455

self.agent_stats = [[0, 0, 0] for a in self.agents]

在阅读别人代码的时候看见的,请问这是什么意思?

4839 次点击
所在节点    Python
31 条回复
mgna17
2016-08-22 20:03:25 +08:00
等号右边返回一个长度与 self.agents 相同的 list ,其中所有元素全是 [0, 0, 0]。
搜索关键字: python 列表生成式
TimePPT
2016-08-22 20:22:04 +08:00
self.agent_stats = []

for A in self.agent:
self.agent_satats.apend([0, 0, 0])
TimePPT
2016-08-22 20:22:25 +08:00
@TimePPT for 循环第二行有缩进
TimePPT
2016-08-22 20:23:11 +08:00
@TimePPT for a in self.agent

手机码字真费劲
jmyz0455
2016-08-22 20:24:16 +08:00
@mgna17 感谢关键词,很多不会的地方都是因为连关键词都想不出来
jmyz0455
2016-08-22 20:24:43 +08:00
@TimePPT 没关系,看懂了,谢谢
introom
2016-08-22 21:20:58 +08:00
应该这样写, self.agent_stats = [ [0] * 3 for _ in range(len(self.agents))]
mingyun
2016-08-22 22:15:46 +08:00
@introom 有什么区别吗
ericls
2016-08-22 22:19:34 +08:00
@mingyun 他这个写法很 pythonic
msg7086
2016-08-23 00:56:12 +08:00
@ericls 比起 [[0] * 3] * len(self.agents) 有什么优势?
Jolly23
2016-08-23 01:22:05 +08:00
类似其他语言的二维数组
ericls
2016-08-23 01:23:46 +08:00
@msg7086 你这个写法更好
josephshen
2016-08-23 02:26:28 +08:00
半夜一觉睡醒了,我可以负责任的对你们说,乘号的写法是错误的,你们试试用一下 id 求一下 list 里面的数据,比较一下值是多少
Sylv
2016-08-23 03:13:41 +08:00
introom
2016-08-23 06:40:50 +08:00
这个算是新手的常见问题吧,我上个礼拜刚给别人解答过。把上次写的直接粘贴复制过来。

>>>>


我补充一下, list 的乘法是浅拷贝,只是复制存储的 PyObject*指针,
所以 a = [[]]*2 ,如果 a[0].append(3), 就会得到[[3], [3]] 而不是[[3], []]
至于为什么这种效果,没办法,人家就是这样设计的,参见
https://hg.python.org/cpython/file/8f84942a0e40/Objects/abstract.c#l928
上面会调用 list 的 sq_repeat , 也就是在这里,
https://hg.python.org/cpython/file/db93af6080e7/Objects/listobject.c#l539
你看,它只是复制了指针。

其实我想补充的是,
对于 python 的多维数组,请不要这样写,
[[0 for i in xrange(4)] for j in xrange(4)],
既然 0 是 immutable ,你完全可以这样写
[[0]*4 for j in xrange(4)]
但是,注意到你都用不到 j 这个变量,我发现你用的是 python2, 在 python2 里, list comprehension 没有新开栈帧,用的是当前函数(或者 module,本质上是 PyFrame)的 local namespace, 换句话说,你这个 j 除了污染当前函数的 local 名字空间以外,别无是处。
建议这样写,
[[0]*4 for _ in xrange(4)]
当然,在 Python3 里, list comphrension 会在一个新的 frame 里执行,不会存在名字空间的污染,不过还是推荐写成_, 因为你根本用不到 j 这个变量。
maowu
2016-08-23 09:12:21 +08:00
@josephshen 能否说明一下为什么错了?
KingHL
2016-08-23 09:59:58 +08:00
楼上已经有人解释的很好了。个人理解, 对于 mutable 对象来说, 用*是不对的, 因为所有的变量名都会指向同一个值,此值改变了,所有的变量都会变。对于 immutable 对象,虽然所有变量名指也向同一个值,但是在改变值的时候,因为原值是 immutable 的,所以被改变的变量名会解引用,重新指向新值的引用,也就不会出问题了。解释的有点不清楚,建议查资料理解下 python 的对象和命名空间的区别。
bravecarrot
2016-08-23 10:07:42 +08:00
@introom 感谢。之前看到过,结果没记住,昨天还刚刚这样用了呢。还有, _ is really a good name.
hitmanx
2016-08-23 11:34:10 +08:00
python 里一直让我比较困惑的就是引用、浅拷贝、深拷贝,可能也和我之前一直用 c/c++有关系。在 c/c++里是按值或按引用 /指针传递,在大部分的情况下是很容易确定的,而且是确定无疑的。在 python 里,我能理解比如最常见的场景: mutable,immutable 涉及到拷贝时产生的状况,但是[[0] * 3] * n 这种情况下会发生什么情况,除了做个实验看一下 id ,我好像还真不敢直接下结论。你们都是怎么记忆的,除了 case by case 的记忆以外,有什么比较通用的规则吗?
qnnnnez
2016-08-23 11:57:48 +08:00
@hitmanx 全部看成传引用就行了,没有隐式拷贝

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/301027

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX