Skip to content

Instantly share code, notes, and snippets.

@niconico25
Last active May 10, 2019 15:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niconico25/4e6c92c18fc44097f3aa0880711f7155 to your computer and use it in GitHub Desktop.
Save niconico25/4e6c92c18fc44097f3aa0880711f7155 to your computer and use it in GitHub Desktop.
#
# そのまま対話モード >>> に
# コピペで実行できます。
#
#
# 再帰的に identity を表示する関数
# Effective Python item 26 を参考にしました。
# http://bit.ly/2HgJAyr
#
def ids(identifier):
# list
if isinstance(identifier, list):
iterator = enumerate(identifier)
# dict
elif isinstance(identifier, dict):
iterator = identifier.items()
# object mutable
elif hasattr(identifier, '__dict__'):
iterator = identifier.__dict__.items()
# object immutable
else:
return id(identifier)
return id(identifier),\
{attribute: ids(value) for attribute, value in iterator}
#
# サンプルクラス
# 常に Obj() == Obj() となるクラスです。
#
class Obj:
def __eq__(self, other):
return type(self) is type(other)
def __repr__(self):
return 'Obj()'
#
# なぜ [[Obj()]*3]*3 掛け算に夜リストの初期化が問題か示します。
#
# NG:
# [[Obj() * 3]] * 3
# OK:
# [[Obj() for i in range(3)] for j in range(3)]
#
# arr1 と arr2 は、ぱっと見て同じに見えます。
arr1 = [[None] * 3] * 3
arr2 = [[None for i in range(3)] for j in range(3)]
assert arr1 == [
[None, None, None],
[None, None, None],
[None, None, None]
]
assert arr2 == [
[None, None, None],
[None, None, None],
[None, None, None]
]
# しかし、操作をしてみるとなにやら違います...
arr1[2][2] = 1
arr2[2][2] = 1
assert arr1 == [
[None, None, 1],
[None, None, 1],
[None, None, 1]
]
assert arr2 == [
[None, None, None],
[None, None, None],
[None, None, 1]
]
# なぜこのようなことが起こったのでしょうか?
# それは
# arr1 には 3 つの要素に同じリストへの参照が入っていたからです。反面、
# arr2 には 3 つの要素に別のリストへの参照が入っていたからです。
assert arr1[0] is arr1[1] is arr1[2]
assert arr2[0] is not arr2[1] is not arr2[2]
#
# ポイント
# 1) 掛け算を使うと
# オブジェクトへの参照を追加します。
# 2) リスト内包表記を使うと
# 新しいオブジェクトを生成します。
#
# arr3 と arr4 は、ぱっと見て同じに見えます。
arr3 = [[Obj()] * 3] * 3
arr4 = [[Obj() for i in range(3)] for j in range(3)]
assert arr3 == [
[Obj(), Obj(), Obj()],
[Obj(), Obj(), Obj()],
[Obj(), Obj(), Obj()],
]
assert arr4 == [
[Obj(), Obj(), Obj()],
[Obj(), Obj(), Obj()],
[Obj(), Obj(), Obj()],
]
#
# しかし identity を表示してみると
# その構成が違うことがわかります。
#
import pprint
pprint.pprint(ids(arr3))
pprint.pprint(ids(arr4))
# >>> pprint.pprint(ids(arr3))
# (4387410568,
# {0: (4387493896, <--- 同じ identity
# {0: (4387582920, {}), 1: (4387582920, {}), 2: (4387582920, {})}),
# 1: (4387493896, <--- 同じ identity
# {0: (4387582920, {}), 1: (4387582920, {}), 2: (4387582920, {})}),
# 2: (4387493896, <--- 同じ identity
# {0: (4387582920, {}), 1: (4387582920, {}), 2: (4387582920, {})})})
# >>> pprint.pprint(ids(arr4))
# (4387493960,
# {0: (4387484360, <--- 異なる identity
# {0: (4387540720, {}), 1: (4387582696, {}), 2: (4387582808, {})}),
# 1: (4387570760, <--- 異なる identity
# {0: (4387582864, {}), 1: (4387583032, {}), 2: (4387583088, {})}),
# 2: (4387571528, <--- 異なる identity
# {0: (4387583144, {}), 1: (4387583200, {}), 2: (4387583256, {})})})
# >>>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment