immutable変数の場合
immutable変数とは
- オブジェクトidを変えずに直接代入されている値の変更が不可能なオブジェクト
- 数値、文字列、タプル、bytes, bool, range
- ただし、タプルは注意
-
("a",1,[1,2,3])
の場合"a"
,1
は変更できないが、[1,2,3]
内の要素は変更できる - それはリストがmutableだから
- なお、
[1,2,3]
そのものを変えること(例えばintに変更)はできない
immutable変数は値を変更できないので、参照後のオブジェクトを変更すると値の再代入になり、元のオブジェクトには影響しない
- immutable変数では
=
で参照したあとに値の変更をしても、元の変数に影響を与えない
c = 1
d = c
c = 99
print(c,d)
d =100
print(c,d)
# out
# 99 1
# 99 100
-
d=c
のタイミングでは、d
はc
を参照しており、オブジェクトidは共通している - しかし、値を再代入(再定義)すると、別のオブジェクトidが発行されるため、cとdの結びつきは解消される
- このため、
=
で参照してもまるでコピーしたかのように振る舞う
c = 1
d = c
print(id(c), id(d))
c = 99
print(id(c), id(d))
d =100
print(id(c), id(d))
# out
# 4486982704 4486982704
# 4486985840 4486982704
# 4486985840 4486985872
ただし、タプルはまたも注意が必要
-
=
でコピーした時点ではオブジェクトidは共通している(下記の例ではL.2の時点ではa
とb
のオブジェクトidは一致) - その状態で下記のように
a[1][0] = "ddd"
やb[1][0] = "xxxx"
といったリスト(mutable object)の変更を行うと、変更が2つのオブジェクトで共通してしまう -
a = (1,2)
のようにタプルを再代入すると元とは別のオブジェクトidが発行されるので、オブジェクトが独立し、互いに干渉しなくなる
a = ("a",["b"])
b = a
a[1][0] = "ddd"
print(a,b)
b[1][0] = "xxxx"
print(a,b)
a = (1,2)
print(a,b)
# out
# ('a', ['ddd']) ('a', ['ddd'])
# ('a', ['xxxx']) ('a', ['xxxx'])
# (1, 2) ('a', ['xxxx'])
mutable変数の場合
mutable変数とは
- オブジェクトidを変えずに直接代入されている値の変更が可能なオブジェクト
- リスト、dict、bytearray, set, classなど
a = [1,2,3,4]
print(id(a))
a[3]=99
print(id(a))
# out
# 4520913608
# 4520913608
参照
- 変数を
=
でつなぐと参照になる - この場合、オブジェクトidが一致する
- 実体が同じものなので、片方のオブジェクトに変更を加えると連動して他方も変更されてしまう
a = [1,2,3,4]
b = a
print(id(a),id(b))
a[3]=99
print(id(a),id(b))
print(a,b)
# out
# 4520977672 4520977672
# 4520977672 4520977672
# [1, 2, 3, 99] [1, 2, 3, 99]
浅いコピー
- 変数を
b = a[:]
のように[:]
をつけてコピーすることで実現- もしくは
b = a.copy()
でも同じ
- もしくは
- 浅いコピーの場合、オブジェクトidは新規に発行される
- 直接代入されているimmutableオブジェクトの取替は連動しない
- 下記の例だと
a[3]=99
はb
に影響を与えていない
- 下記の例だと
a = [1,2,3,4]
b = a.copy()
print(id(a),id(b))
a[3]=99
print(id(a),id(b))
print(a,b)
# out
# 4517479560 4521704008
# 4517479560 4521704008
# [1, 2, 3, 99] [1, 2, 3, 4]
- ただし、オブジェクト内のmutableオブジェクトに対する変更は連動する
- 下記の例では、
a[1][1]=99
の操作がリストa
(mutable)の中のリスト(mutable)のindex=1の値を変更しているが、その操作はb
にも影響している - 一方で、
a[0]=99
は、リストa
(mutable)の中の整数(imutable)の値を再代入しているので、b
には連動しない
- 下記の例では、
a = [1,[2,3]]
b = a.copy()
print(id(a),id(b))
a[0]=99
print(id(a),id(b))
a[1][1]=99
print(id(a),id(b))
print(a,b)
# out
# 4358824520 4358826184
# 4358824520 4358826184
# 4358824520 4358826184
# [99, [2, 99]] [1, [2, 99]]
深いコピー
-
import copy
の上で、copy.deepcopy(a)
で実現 - 連動しない
import copy
a = [1,[2,3]]
b = copy.deepcopy(a)
print(id(a),id(b))
a[0]=99
print(id(a),id(b))
a[1][1]=99
print(id(a),id(b))
print(a,b)
# out
# 4521762760 4521742728
# 4521762760 4521742728
# 4521762760 4521742728
# [99, [2, 99]] [1, [2, 3]]