Re: [问题] a[1:3]会马上复制吗?

楼主: why8ther (外八喵)   2015-07-22 10:27:49
※ 引述《why8ther (外八喵)》之铭言:
: 已知:
: b = [2, 3]
: >>> b[0] = 99
: b = [99, 3]
: a = [1, 2, 3, 4]
: 由此可知,黄色那行的值并不会改动到a阵列,而是创造一个副本了
: 我的问题是 :
: 这个副本是(1) 在我呼叫a[1:3]时就被创造了?
: 抑或(2) 直到我改动b[0]才被创造,若不改动就永远参照本来阵列
: 因为最近遇到比较高的性能要求 需要弄清楚@@
: 第一次po文 请大家多多指教
自己回自己的文XDD
其实应该是有实作copy on write的
根据这篇stack overflow http://goo.gl/XcgHG6
我自己实验也是一样的结果
>>> a = [1,2,3]
>>> b = a[1:3]
>>> id(a[1])
1440535008
>>> id(b[0])
1440535008
>>> b[0] = 123
>>> a
[1, 2, 3]
>>> b
[123, 3]
>>> id(a[1])
1440535008
>>> id(b[0])
1440536944 变得不一样了!!
>>> id(a[2])
1440535024
>>> id(b[1]) 但a[2]和b[1]没有被改动,仍是同一个
1440535024
不过虽说是copy on write,但我推测应该还是复制了阵列中每个元素的referance
而不只是阵列本身的referance
推测根据就是上面那行红字。
若本来阵列长度是100,就等于复制了100份的参照。
所以比较适合的状况应该是:
阵列中每个物件很大,但阵列本身较短
反之,若阵列元素很小(像是int)
那复制参照跟直接复制应该就没啥差别惹。
大概是这样
作者: LiloHuang (十年一刻)   2015-07-22 10:51:00
http://goo.gl/CpWviL Python 会直接建立新的 list把 reference 拷贝过去,这并不算是 Copy-on-write毕竟拷贝的行为还是产生了,而且并不是在 write 时拷贝所以不能称之为是完整的 copy-on-write。
作者: uranusjr (←這人是超級笨蛋)   2015-07-22 11:35:00
这根本就不是 copy-on-write, 无所谓完不完整啊你在 C++ 拷贝 list<int *> 也会有类似行为, 但根本不会有人把它叫做 copy-on-write, 因为它就是单纯的 copy
作者: LiloHuang (十年一刻)   2015-07-22 11:43:00
我必须要修正我的用语,这不是"真正"的 copy-on-write谢谢 uranusjr 的补充 :)真正的 copy-on-write 是在 write 时拷贝物件,即便是reference 也要在 write 时才被拷贝,而不是一开始拷贝如果有一亿个 list elements 搭配 COW,不会有 O(n) 的拷贝成本存在于建立第二份 list 时另外之所以我会用是否"完整"的用词是维基百科对于 COW的定义,某种策略上是有用指标来只到原始版本的https://goo.gl/HiAM5V 但是我不认为这是真正的COW就是因为真正大家谈及的COW,都是像 fork child process在还没有修改原始版本前,不应该存在有额外的消耗就是或者应该说 C++ 拷贝 list<Foobar *> 假设 Foobar 是成本超高的大物件,在写入时作出副本,也是某种程度的COW,对于该大物件而言。只是 Python 根本就是建立了新物件,然后把参照给换掉,因为数字是 immutable obj跟 COW 的策略一点关系都没有,因为新物件不是它建立的真正的 COW 要是全自动的,对使用者来说是透明无感的。另外如同维基百科写的 std::string 有 COW 实作有空的人不仿可以看看实作方法,我相信是拷贝指标 :P因此用"完整"一词会更好,完整的COW连指标都不会拷贝但这还是端看实作,跟到底被 COW 的对象是什么物件而定

Links booklink

Contact Us: admin [ a t ] ucptt.com