Last active
May 10, 2019 15:19
-
-
Save niconico25/4e6c92c18fc44097f3aa0880711f7155 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# | |
# そのまま対話モード >>> に | |
# コピペで実行できます。 | |
# | |
# | |
# 再帰的に 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