« 引っ越しまだしてない日記 |Main| インターネット買った日記 »

« Haskell In Python ver. 0.01 | Python | Pythonで日本語PDFをつくるサンプル »

immutableクイズ

空欄を埋めよ。
>>> dic = {}
(空欄)
>>> dic
{[1]: 1, [2]: 2, [3]: 3}
>>> for k in dic.keys():
	k.append(0)

	
>>> dic
{[1, 0]: 1, [2, 0]: 2, [3, 0]: 3}

答えは2通り以上あるけど、、どういうのとどういうの、っていうとヒントになるから言わない。

ファインマンが 「小学校の教科書で『電車はなぜ動くのでしょう?それはエネルギーが動かすからです』なんて説明はまずくないか?それを習った生徒が『エネルギー』という言葉なしで習ったことを説明できるか?できないのは、結局言葉の定義以外を覚えただけだからじゃないのか?」というようなことを言っていた。 で、(im)mutableという言葉を使わずになぜPythonの辞書にはリストが入れられないのかを説明できるだろうか?

初心者向けの解説で「リストはミュータブル(変更できる)ので辞書には入れられません」なんて説明をするのはやめたほうがいいのではないだろうか。

答えは30cm下で書く。

>>> dic = {}
>>> class Foo(object):
	def __init__(self, vs):
		self.value = vs
	def __repr__(self):
		return repr(self.value)
	def append(self, v):
		self.value.append(v)

		
>>> dic[Foo([1])] = 1
>>> dic
{[1]: 1}
>>> class Bar(list):
	def __hash__(self):
		return id(self)

	
>>> dic[Bar([2])] = 2
>>> dic
{[1]: 1, [2]: 2}
>>> class Baz(list):
	def __hash__(self):
		return sum(self)

	
>>> dic[Baz([3])] = 3
>>> dic
{[1]: 1, [2]: 2, [3]: 3}
>>> for k in dic.keys():
	k.append(0)

	
>>> dic
{[1, 0]: 1, [2, 0]: 2, [3, 0]: 3}
このように、辞書にリストを入れること自体は別に難しいことではない。 ではなぜ、わざわざ辞書にリストが入らないようにしてあるのだろうか?

id(オブジェクトの同一性)を使って区別をするFooとBarの場合、下のような現象が起きる。

>>> dic2 = {}
>>> dic2[Bar([])] = 1
>>> dic2[Bar([])] = 2
>>> dic2[Bar([1])] = 3
>>> dic2[Bar([1])] = 4
>>> dic2
{[]: 1, []: 2, [1]: 4, [1]: 3}
1つ目の[]と2つ目の[]は別物だから。 下のコードはエラーになる。
>>> dic = {}
>>> dic[Bar([])] = 1
>>> dic
{[]: 1}
>>> k = Bar([])
>>> k
[]
>>> print dic[k]

Traceback (most recent call last):
  File "", line 1, in -toplevel-
    print dic[k]
KeyError: [] # 1つ目の[]と2つ目の[]は別物なのでキーが見つからない

中身を見て区別をする(同じ中身のものは同じと見なす)ようにすると、 この現象は起こらなくなる。

>>> dic = {}
>>> dic[Baz([1, 2])] = 1
>>> dic
{[1, 2]: 1}
>>> k = Baz([1, 2])
>>> k
[1, 2]
>>> print dic[k]
1
しかし、中身で分類しているので、中身を書き換えられると困る。 中身の合計が3だから3の棚にしまったので 6の棚を探しても見つからない。
>>> k = dic.keys()[0]
>>> k
[1, 2]
>>> k.append(3)
>>> k
[1, 2, 3]
>>> dic
{[1, 2, 3]: 1}
>>> print dic[Baz([1, 2, 3])]

Traceback (most recent call last):
  File "", line 1, in -toplevel-
    print dic[Baz([1, 2, 3])]
KeyError: [1, 2, 3]
こうなったら書き換えられないリストを作るしかないんじゃない? というわけでタプルが生まれたのではないかと思う。

トラックバック(Trackback)

Trackback URL: http://www.nishiohirokazu.org/mt/mt-tb.cgi/549

フィードバック

by m-wada | 2007年03月30日 20:35

python使用暦もうすぐ2年ですがぶっちゃけわかりません。ちょっと考えてみます。が、現状の自分には考えるよりライブラリリファレンスを漁る必要があるのだろうと思います。案の定ミュータブルという言葉も今知りました。 答えのついでにこれはどういった場合に利用されるテクなのか知りたいところですね。

「辞書(ハッシュ)とはどういうものか」 の理解度を試すテクかな…。なにかプログラムを作る上で役に立つわけではないです。

by しみずかわ | 2007年03月30日 23:01

listにdelegateしたclassを作る。うーん、行数長いなあ...

それが一つの解です。上の例ならappendだけ中継すれば済むのでまぁ、さほど問題ではないですね。もう一つの解はもっと短いです。

by aodag | 2007年03月31日 06:38

listを継承して__hash__をオーバーライド

それがもう一つの解ですね。

ご意見・ご感想をお送りください(フィードバック)

(フィードバックはメールで送信され、基本的に表示されませんが、内容によっては公開させていただくこともございます。ご了承ください。Your comment doesn't appear the page immediately. If the comment has value to other people, it will be put on the page or subsequent entries. Thank you.)

上の情報は、いずれも未記入でかまいません。 All of above questions are optional.