星期六, 三月 03, 2007

Copy Semantics in Python

昨天晚上被Python给整得……还是自己概念不清。我想实现一个二维数组,最直接的办法就是用list,其中每个元素又是一个list。所以我就这么写了:

array2d = [[]]*n ## n is the dimension of the 2-d array

然后要往里添加元素。像这样:

array2d[0].append(1)

我很自信的认为结果肯定会得到[[1],[],...,[]]。所以根本就没去检查。整个算法跑出来得到一堆诡异的结果,然后就开始了艰苦的bug hunting。找了半天,问题集中在前面那条append语句。print出来一看,结果居然是[[1],[1],...,[1]]!看到这个输出我愣了半天,我觉得我的世界观人生观都被打碎了。问题当然出在Python的copy by reference的语义上。在通过'*'运算符复制时,复制的只是“引用”,复制出来的所有东西其实都是同一个。我当时还没把问题想明白,复制不行,咱们就累一点,一个一个添加进去!

array2d = []
for i in range(n):
array2d.append([])


这个做法是正确的,用id()检查array2d的每一个元素发现它们各不相同。然后我又犯傻了,想把它写成一个函数:

def new_array2d(n,obj):
ret = []
for i in range(n):
ret.append(obj)
return ret

结果又回到了老路上,再一次出错。

最后来总结经验:Python中的复制(这里的复制其实包括了赋值、参数传递、‘*’运算符(仅对sequence type有效)等等)是by reference的。如果复制的对象是immutable的,比如int,string,那么by reference和by value其实没有区别。但如果对象是mutable的,比如list,dictionary,那么复制就相当于C中的复制指针,这个时候要提起注意。那么为什么前面写array2d.append([])的时候不会出问题呢?表达式'[]'会导致一个新的list对象被构造出来,虽然大家都是[],但各不相同。它们是“值”相等,但“引用”不相等。这也是因为list是可变对象。其实copy by reference的语义pythonist估计都知道,但到实际编码的时候还是免不了要犯一点错。

再想想,如果真的要copy一个list,得到一个副本呢?Python给我们提供了copy模块专门来做这件事。copy提供了两个基本的函数,一个是copy,一个是deep_copy。copy.copy(obj)函数提供了Shallow Copy语义,copy.deep_copy(obj)顾名思义是Deep Copy。两者的区别相信学过C++中Copy Constructor的同志都很明白。一般情况下,用copy.copy(obj)就可以了(所以它的名字就叫copy,没有弄成shallow_copy()这样的怪胎)。这个办法我想应该比较普适。当然,对于list,我们有专门的惯用法(即切片操作[:])复制。又如字典(dict)对象,也有相应的copy方法,一般情况下不需要动用到copy模块。

Python中Copy模块的文档

终于,找到了在blogger中显示代码缩进的办法:输入全角空格。这样就不会被自作聪明的blogger把空格都去掉了。缺点是:如果有人想把代码拷贝到文本编辑器中,就会出现一堆非法字符(我相信没有哪种语言的编译器/解释器会把全角空格当作空格的)。然后就会扔出a mass of error message。所以这也只是权宜之计。或许修改css能够解决这个问题?
Update:和Python无关,终于找到了代码缩进问题的解决办法,很简单,把所见即所得编辑器关掉,直接写html,把代码放在pre标签中。

18 条评论:

Corsair 说...

Clone 一个 list 可以这样:

NBList = ["N", "B"]
SBList = NBList[:]

逆円助 说...

さあ、今夏も新たな出会いを経験してみませんか?当サイトは円助交際の逆、つまり女性が男性を円助する『逆円助交際』を提供します。逆円交際を未経験の方でも気軽に遊べる大人のマッチングシステムです。年齢上限・容姿・経験一切問いません。男性の方は無料で登録して頂けます。貴方も新たな出会いを経験してみませんか

精神年齢 说...

みんなの精神年齢を測定できる、メンタル年齢チェッカーで秘められた年齢がズバリわかっちゃう!かわいいあの子も実は精神年齢オバサンということも…合コンや話のネタに一度チャレンジしてみよう

メル友募集 说...

最近仕事ばかりで毎日退屈してます。そろそろ恋人欲しいです☆もう夏だし海とか行きたいな♪ k.c.0720@docomo.ne.jp 連絡待ってるよ☆

家出 说...

最近TVや雑誌で紹介されている家出掲示板では、全国各地のネットカフェ等を泊り歩いている家出娘のメッセージが多数書き込みされています。彼女たちはお金がないので掲示板で知り合った男性の家にでもすぐに泊まりに行くようです。あなたも書き込みに返事を返してみませんか

動物占い 说...

あなたの性格を、動物に例えて占っちゃいます。もしかしたらこんな動物かも!?動物占いをうまく使って、楽しい人間関係を築いてください

家出 说...

家出中の女性や泊まる所が無い女性達がネットカフェなどで、飲み放題のドリンクで空腹を満たす生活を送っています。当サイトはそんな女性達をサポートしたいという人たちと困っている女性たちの為のサイトです

セレブラブ 说...

セレブ女性との割り切りお付き合いで大金を稼いでみませんか?女性に癒しと快楽、男性に謝礼とお互い満たしあえる当サイト、セレブラブはあなたの登録をお待ちしております。

夏フェス!! 说...

夏フェス一緒に行ってくれる人募集!!夏の思い出一緒につくろぉ☆ megumi-0830@docomo.ne.jp 連絡してね♪

無料ゲーム 说...

あなたのゲーマー度を無料ゲーム感覚で測定します。15個の質問に答えるだけの簡単測定で一度遊んでみませんか?ゲームが得意な人もそうでない人もぜひどうぞ。

素人 说...

Hな女性たちは素人ホストを自宅やホテルに呼び、ひとときの癒しを求めていらっしゃいます。当サイトでは男性ホスト様の人員が不足しており、一日3~4人の女性の相手をするホストもおられます。興味を持たれた方は当サイトにぜひお越しください

出会い系 说...

実は出会い系には…関係者用入り口があるのを知っていますか?広告主やスポンサー用に用意されたIDではサクラや業者が立ち入ることが出来ないようになっているのです。当サイトでは極秘に入手した関係者用URLが公開されています

逆援助 说...

男性はお金、女性は快楽を得る逆援助に興味はありませんか?お金を払っても性的欲求を満たしたいセレブ達との割り切り1日のお付き合いで当サイトでは大金を得ることができます。無料登録なのでアルバイト感覚でOK、詳しくはTOPページでどうぞ。

友達募集 说...

ホムペ完成記念!私の事みんなに知ってもらいたくて頑張りましたぁ。色々とご感想をお待ちしているので思った事を意見してください。メアドはほむぺにのせてありますぅ!★ fan.jna@docomo.ne.jp

家出 说...

夏休みで気軽に家出する女子○生が急増しています。しかし家出したはいいものの泊る所やお金が無い彼女たちは、掲示板などで泊めてくれる男性を探す子も多いようです。当掲示板にも夏休みに入ってから通常の3倍以上のメッセージが寄せられています

人妻 说...

今最もアツイバイトは人妻とのセフレ契約です。当サイトではお金を払ってでもセフレがほしい人妻が集まり、男性会員様との逆援生活を待っています。当サイトで欲求不満の女性との出会いをしてみませんか

素人 说...

素人ホストでは、男性のテクニック次第で女性会員様から高額な謝礼がもらえます。欲求不満な人妻や、男性と出会いが無い女性達が当サイトで男性を求めていらっしゃいます。興味のある方はTOPページからどうぞ

友達募集中 说...

少し魅惑な自分をネットだから公開してみました。普段言えない事など、思い切って告白しているプロフなので興味ある方はぜひ除いてみてください連絡待ってまぁす。 hinyaaaaa@docomo.ne.jp