Pythonでは、リストのようなオブジェクトは代入では参照になる。
a = [ 1, 2 ]
b = a
b[1] = 3
print a # [1, 3]
copyを使うと成分をコピーする。
import copya = [ 1, 2 ]
b = copy.copy(a)
b[1] = 3
print b # [1, 3]
print a # [1, 2]
ただし、深いコピー(ディープコピー)はしない。
import copya = [ [1, 2], [3, 4] ]
b = copy.copy(a)
b[1][1] = 3
print b # [ [1, 2], [3, 3] ]
print a # [ [1, 2], [3, 3] ]
ディープコピーは次のようにする。
import copya = [ [1, 2], [3, 4] ]
b = copy.deepcopy(a)
b[1][1] = 3
print b # [ [1, 2], [3, 3] ]
print a # [ [1, 2], [3, 4] ]
ディープコピーはどこまでも深くコピーするので、注意が必要である。適当な深さまでコピーしたい場合は、クラスなら__copy__を定義すればよい。
例えば、2次元の点と線を次のように定義する。
class cEdge:
def __init__(self, vs, ve):
self.v = [ vs, ve ]
def __str__(self):
return str(self.v[0]) + " - " + str(self.v[1])class cVertex:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "(" + str(self.x) + ", " + str(self.y) + ")"
これをコピーして、点を変えると、
v1 = cVertex(1, 2)
v2 = cVertex(2, 3)
v3 = cVertex(3, 4)
e1 = cEdge(v1, v2)
e2 = copy.copy(e1)
e2.v[1] = v3
print e1 # (1, 2) - (3, 4)
変えていないつもりの辺まで変わってしまう。
それではということでディープコピーを使って、点の座標を変えると、
v1 = cVertex(1, 2)
v2 = cVertex(2, 3)
e1 = cEdge(v1, v2)
e2 = copy.deepcopy(e1)
e2.v[1].x = 3
print e1 # (1, 2) - (2, 3)
今度は点を動かしたつもりなのに動いてくれない。
このようなときは、クラスに__copy__メソッドを定義するとよい。
import copyclass cEdge:
def __init__(self, vs, ve):
self.v = [ vs, ve ]
def __str__(self):
return str(self.v[0]) + " - " + str(self.v[1])
def __copy__(self):
e = cEdge(self.v[0], self.v[1])
return eclass cVertex:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "(" + str(self.x) + ", " + str(self.y) + ")"v1 = cVertex(1, 2)
v2 = cVertex(2, 3)
v3 = cVertex(3, 4)
e1 = cEdge(v1, v2)
e2 = copy.copy(e1)
e2.v[1].x = 3
print e1 # (1, 2) - (3, 3)
e2.v[1] = v3
print e1 # (1, 2) - (3, 3)