1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

immutable/mutable変数の参照・浅いコピー・深いコピーに関して

Last updated at Posted at 2019-03-20

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のタイミングでは、dcを参照しており、オブジェクト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の時点ではabのオブジェクト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]=99bに影響を与えていない
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]]
1
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?