Skip to content

Instantly share code, notes, and snippets.

@caprest
Created October 9, 2017 15:30
Show Gist options
  • Save caprest/002ec50182adfbf6df68618762f44533 to your computer and use it in GitHub Desktop.
Save caprest/002ec50182adfbf6df68618762f44533 to your computer and use it in GitHub Desktop.
pythonのあれ

大前提

pythonの代入はすべて参照渡しらしいが、参照先での値変更について挙動がいろいろと異なるらしい。 pythonのオブジェクトはimmutable(変更不可)なものと、mutable(変更可能)なものがあり、mutableなものについては、参照先で値が変更されると元のオブジェクトの値も変更されるようだ。

結論から言うと以下の挙動はlistがmutableで、intがimmutableなことからおこるらしい。

a = [0]*3
print(id(a[0]),id(a[1]),id(a[2]))
139808821021184 139808821021184 139808821021184
a[0]  = 1
print(a)
print(id(a[0]),id(a[1]),id(a[2]))
[1, 0, 0]
139808821021216 139808821021184 139808821021184

たしかに変化した部分だけアドレスが変わっている。

b =[[0]*3] *3 
print(id(b[0][0]),id(b[0][1]),id(b[1][0]))
print(id(b[0]),id(b[1]))
b[0][0] = 1
print(b)
print(id(b[0][0]),id(b[0][1]),id(b[1][0]))
139808821021184 139808821021184 139808821021184
139808366470920 139808366470920
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
139808821021216 139808821021184 139808821021216
要するになぜこれが起きるかというとリストはmutableなオブジェクトでb[0]~b[2]のアドレスが一致しているため3つとも値が変更されるということらしい下に回避方法を書いた
d = [[0]*3 for _ in range(3)]
print(id(d[0]),id(d[1]))
d[0][0]  = 1
print(d)
139808366538632 139808366474440
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]

なおintとかも普通に代入されてるやん!という突っ込みをしたくなるが、どうも以下のように代入をする場合はは新しいオブジェクトになっている模様。 変更不可なことの例としては複素数が分かりやすかった。

a =4
print(id(a))
a = 5
print(id(a))
139808821021312
139808821021344
a = 4 + 3j
a.imag  = 4
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-54-6e8c72133bc5> in <module>()
      1 a = 4 + 3j
----> 2 a.imag  = 4


AttributeError: readonly attribute

ちなみにnumpyでやると

import numpy as np
A = np.repeat([0], 3)
B = np.array([0]*3)
print(id(A[0]),id(A[1]),id(A[2]))
print(id(B[0]),id(B[1]),id(B[2]))
AA = np.tile([0],[3,3])
print(id(AA[0][0]),id(AA[1][0]),id(AA[2][0]))
AA[0][0] = 3
print(id(AA[0][0]),id(AA[1][0]),id(AA[2][0]))
c = np.array([[0]*3] *3 )
c[0][0] = 1
c
139808367363848 139808367363848 139808367363848
139808367363848 139808367363848 139808367363848
139808367363848 139808367363848 139808367363848
139808367363848 139808367363848 139808367363848





array([[1, 0, 0],
       [0, 0, 0],
       [0, 0, 0]])

そもそも一つのオブジェクトとして宣言されるっぽいので調査の意味がなかった。pythonマスターへの道は果てしない。

参考 http://amacbee.hatenablog.com/entry/2016/12/07/004510 twitterを見て書き始めたのだが、結局この記事の劣化版になってしまった。pythonの実装はちゃんと読もうね。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment