作者why8ther (外八喵)
看板Python
標題Re: [問題] a[1:3]會馬上複製嗎?
時間Wed Jul 22 10:27:49 2015
※ 引述《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)
那複製參照跟直接複製應該就沒啥差別惹。
大概是這樣
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 140.96.27.107
※ 文章網址: https://webptt.com/m.aspx?n=bbs/Python/M.1437532071.A.759.html
※ 編輯: why8ther (140.96.27.107), 07/22/2015 10:35:45
2F:→ LiloHuang: 把 reference 拷貝過去,這並不算是 Copy-on-write 07/22 10:51
3F:→ LiloHuang: 畢竟拷貝的行為還是產生了,而且並不是在 write 時拷貝 07/22 10:54
4F:→ LiloHuang: 所以不能稱之為是完整的 copy-on-write。 07/22 10:54
5F:→ uranusjr: 這根本就不是 copy-on-write, 無所謂完不完整啊 07/22 11:35
6F:→ uranusjr: 你在 C++ 拷貝 list<int *> 也會有類似行為, 但根本不會 07/22 11:36
7F:→ uranusjr: 有人把它叫做 copy-on-write, 因為它就是單純的 copy 07/22 11:36
8F:推 LiloHuang: 我必須要修正我的用語,這不是"真正"的 copy-on-write 07/22 11:43
9F:→ LiloHuang: 謝謝 uranusjr 的補充 :) 07/22 11:43
10F:→ LiloHuang: 真正的 copy-on-write 是在 write 時拷貝物件,即便是 07/22 11:45
11F:→ LiloHuang: reference 也要在 write 時才被拷貝,而不是一開始拷貝 07/22 11:45
12F:→ LiloHuang: 如果有一億個 list elements 搭配 COW,不會有 O(n) 的 07/22 11:46
13F:→ LiloHuang: 拷貝成本存在於建立第二份 list 時 07/22 11:46
14F:→ LiloHuang: 另外之所以我會用是否"完整"的用詞是維基百科對於 COW 07/22 11:48
15F:→ LiloHuang: 的定義,某種策略上是有用指標來只到原始版本的 07/22 11:48
17F:→ LiloHuang: 因為真正大家談及的COW,都是像 fork child process 07/22 11:50
18F:→ LiloHuang: 在還沒有修改原始版本前,不應該存在有額外的消耗就是 07/22 11:51
19F:→ LiloHuang: 或者應該說 C++ 拷貝 list<Foobar *> 假設 Foobar 是 07/22 11:52
20F:→ LiloHuang: 成本超高的大物件,在寫入時作出副本,也是某種程度的 07/22 11:53
21F:→ LiloHuang: COW,對於該大物件而言。只是 Python 根本就是建立了 07/22 11:53
22F:→ LiloHuang: 新物件,然後把參照給換掉,因為數字是 immutable obj 07/22 11:53
23F:→ LiloHuang: 跟 COW 的策略一點關係都沒有,因為新物件不是它建立的 07/22 11:56
24F:→ LiloHuang: 真正的 COW 要是全自動的,對使用者來說是透明無感的。 07/22 12:02
25F:→ LiloHuang: 另外如同維基百科寫的 std::string 有 COW 實作 07/22 12:02
26F:→ LiloHuang: 有空的人不仿可以看看實作方法,我相信是拷貝指標 :P 07/22 12:02
27F:推 LiloHuang: 因此用"完整"一詞會更好,完整的COW連指標都不會拷貝 07/22 12:06
28F:→ LiloHuang: 但這還是端看實作,跟到底被 COW 的對象是什麼物件而定 07/22 12:07
想一想這樣應該真的不算COW...
python的複製本來就只是複製referance
剛剛發文的時候觀念突然跑掉...抱歉...
※ 編輯: why8ther (140.96.27.107), 07/22/2015 13:06:45