Re: [問題] a[1:3]會馬上複製嗎?

看板Python作者 (外八喵)時間10年前 (2015/07/22 10:27), 10年前編輯推噓3(3025)
留言28則, 2人參與, 最新討論串2/2 (看更多)
※ 引述《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://www.ptt.cc/bbs/Python/M.1437532071.A.759.html ※ 編輯: why8ther (140.96.27.107), 07/22/2015 10:35:45

07/22 10:51, , 1F
http://goo.gl/CpWviL Python 會直接建立新的 list
07/22 10:51, 1F

07/22 10:51, , 2F
把 reference 拷貝過去,這並不算是 Copy-on-write
07/22 10:51, 2F

07/22 10:54, , 3F
畢竟拷貝的行為還是產生了,而且並不是在 write 時拷貝
07/22 10:54, 3F

07/22 10:54, , 4F
所以不能稱之為是完整的 copy-on-write。
07/22 10:54, 4F

07/22 11:35, , 5F
這根本就不是 copy-on-write, 無所謂完不完整啊
07/22 11:35, 5F

07/22 11:36, , 6F
你在 C++ 拷貝 list<int *> 也會有類似行為, 但根本不會
07/22 11:36, 6F

07/22 11:36, , 7F
有人把它叫做 copy-on-write, 因為它就是單純的 copy
07/22 11:36, 7F

07/22 11:43, , 8F
我必須要修正我的用語,這不是"真正"的 copy-on-write
07/22 11:43, 8F

07/22 11:43, , 9F
謝謝 uranusjr 的補充 :)
07/22 11:43, 9F

07/22 11:45, , 10F
真正的 copy-on-write 是在 write 時拷貝物件,即便是
07/22 11:45, 10F

07/22 11:45, , 11F
reference 也要在 write 時才被拷貝,而不是一開始拷貝
07/22 11:45, 11F

07/22 11:46, , 12F
如果有一億個 list elements 搭配 COW,不會有 O(n) 的
07/22 11:46, 12F

07/22 11:46, , 13F
拷貝成本存在於建立第二份 list 時
07/22 11:46, 13F

07/22 11:48, , 14F
另外之所以我會用是否"完整"的用詞是維基百科對於 COW
07/22 11:48, 14F

07/22 11:48, , 15F
的定義,某種策略上是有用指標來只到原始版本的
07/22 11:48, 15F

07/22 11:48, , 16F
https://goo.gl/HiAM5V 但是我不認為這是真正的COW就是
07/22 11:48, 16F

07/22 11:50, , 17F
因為真正大家談及的COW,都是像 fork child process
07/22 11:50, 17F

07/22 11:51, , 18F
在還沒有修改原始版本前,不應該存在有額外的消耗就是
07/22 11:51, 18F

07/22 11:52, , 19F
或者應該說 C++ 拷貝 list<Foobar *> 假設 Foobar 是
07/22 11:52, 19F

07/22 11:53, , 20F
成本超高的大物件,在寫入時作出副本,也是某種程度的
07/22 11:53, 20F

07/22 11:53, , 21F
COW,對於該大物件而言。只是 Python 根本就是建立了
07/22 11:53, 21F

07/22 11:53, , 22F
新物件,然後把參照給換掉,因為數字是 immutable obj
07/22 11:53, 22F

07/22 11:56, , 23F
跟 COW 的策略一點關係都沒有,因為新物件不是它建立的
07/22 11:56, 23F

07/22 12:02, , 24F
真正的 COW 要是全自動的,對使用者來說是透明無感的。
07/22 12:02, 24F

07/22 12:02, , 25F
另外如同維基百科寫的 std::string 有 COW 實作
07/22 12:02, 25F

07/22 12:02, , 26F
有空的人不仿可以看看實作方法,我相信是拷貝指標 :P
07/22 12:02, 26F

07/22 12:06, , 27F
因此用"完整"一詞會更好,完整的COW連指標都不會拷貝
07/22 12:06, 27F

07/22 12:07, , 28F
但這還是端看實作,跟到底被 COW 的對象是什麼物件而定
07/22 12:07, 28F
想一想這樣應該真的不算COW... python的複製本來就只是複製referance 剛剛發文的時候觀念突然跑掉...抱歉... ※ 編輯: why8ther (140.96.27.107), 07/22/2015 13:06:45
文章代碼(AID): #1Lhl-dTP (Python)
討論串 (同標題文章)
文章代碼(AID): #1Lhl-dTP (Python)