a = [1] では、変数名 a が、リストオブジェクト [1] に結び付けられます
さらに b = a を行うと、b は a
と同じリストオブジェクトを指すようになります。
つまり、b は a の別名のように働きます。
そのため、b.append(2) は もとのオブジェクト [1] と a も
[1,2]に変えます。
このように、pythonの変数への代入はは、他の言語の「参照の代入」に似た振る舞いをします。
さらに b = [] を実行すると、b は obj, a とは切り離され、新しいオブジェクト [] を指します
関数内で基本変数型の引数への代入が関数の呼び出しもとに影響を与えないことは他の言語と同じですが
(代入の副作用は同じ)、
pythonでは、python特有の仕様で実現しています。興味のある方は以下の説明を読んでください。
引数変数で渡された整数型などを関数内で変更する場合、例えば以下のようになります。
def func(i):
i = 3
i = 5
print("1: i=", i)
func(i)
print("2: i=", i)
他の多くのプログラム言語と同様
(初期のBASICなどは例外です)、1:の i は 5 で、2: の i も5
のままで、func()中での変更は反映されません。
これは、他のプログラム言語では関数への引数は値渡しをしているため、関数内の変数の実体は関数の呼び出し元の変数とは異なるためです。
一方、上記の通りpythonでは基本変数型を含めて全て参照の値渡しをしています。それにもかかわらず、関数内で変数に代入しても、呼び出し元の変数の値には影響を与えません。これは、下記のように変数への代入では代入する変数・値の参照に置き換えることで値を変えているためです。この機構により、関数内での値の変更は関数の呼び出しもとの値に影響を与えないようになっています。
例えば、上記の i = 5 の i のアドレスを XXXX とします。
func(i) 中での i = 3 では、3 のアドレスを YYYY とすると、i
のアドレスは YYYY に置き換わります。この i
は、func(i)の局所変数です。
func() の外部の i はfunc(i)の局所変数 i
と別ですので、値は変わりません。
ただし、イミュータブルなオブジェクトのすべての内部の値を変更できないわけではありません。
タプルはイミュータブルなので
a = (1, 2, 3)
a[0] = 3
はエラーになりますが、
a = ([], [], [])
a[0].append(3)
は問題ありません。変更できないのは 、タプルの各要素がどのオブジェクトを指すか、という対応関係です。
オブジェクトの例 (仮想コード)
catオブジェクト: propertyとして、color, weight, methodとして move(), position()などが考えられる。
# クラスの定義 (概念的なプログラムリストなので以下のままでは動かない):
class Cat():
# pythonでは、 # 以降は行末までがコメント文として、無視される
# 関数は def文で定義し、: で終わる
# 変数は 変数名 = 初期値 とすることで、初期値を設定できる
def __init__(self, color = 'white', weight = 20.0):
self.color = color
self.weight = weight
self.x = 0.0 # 位置変数 x,y,zは 0.0 で初期化しておく
self.y = 0.0
self.z = 0.0
def move(self., dx, dy, dz): # 位置をdx,dy,dzだけ移動させる
self. z += dx
self.y += dy
self. z += dz
def position(self):
return self. x, self.y, self.z # 位置を [x,y,z]リストで返すメソッド
インスタンスの生成(変数の作成)
nyanko = Cat() # catクラスで定義されたオブジェクトのインスタンス変数nyankoをつくる。
# 引数を指定していないので、初期値が使われ、
# naynako.color は 'white'、nyanko.weightは 20kgになる。
nyanko = Cat(color = 'black')
# catクラスで定義されたオブジェクトのインスタンス変数nyankoをつくる。
# 引数で指定されたcolor変数は初期値から変更され、naynako.color は 'black' になる
nyanko.move(3, -1, 0)を実行すると、nyanko.x, nyanko.y, nyanko.zはそれぞれ 3, -1, 0 になる
nyanko.move(-1, 3, 2)を実行すると、nyanko.x, nyanko.y, nyanko.zはそれぞれ 2, 2, 2 になる