Pythonの変数と代入について説明します。
Pythonの基本
Pythonの値(データ)は総てオブジェクトです。
None、数値、真偽値、文字列、リスト、関数、クラス、メソッド、その他 総てがオブジェクトです。
オブジェクトはメモリ上に生成され、オブジェクトを識別するオブジェクト識別子(オブジェクトID)が与えられます。
変数に値を代入すると、値そのものではなくオブジェクトIDを保持して、変数からオブジェクトを参照します。
オブジェクトIDはid()
関数で調べる事ができます。
変数解釈
Pythonの変数をどう考えるかで解釈が二つあります。
箱解釈
変数を値(データ)が入る箱と解釈します。
A = 1
この代入文は、Pythonでは
「数値1のオブジェクトIDを A
という名前の箱に入れる」
と解釈します。
名札解釈
変数はオブジェクトに対する名札と解釈します。
A = 1
この代入文は
「数値1 に A
という名札を付ける(束縛する)」
と解釈します。
代入
代入の動作について説明します。
箱解釈で説明します。
数値オブジェクト
A = 1 # 数値1がメモリ上に生成され、数値1のオブジェクトIDが変数Aに代入されます。
B = A # 変数Aが保持してるオブジェクトIDが変数Bにも代入されます。
A = 2 # 数値2がメモリ上に生成され、数値2のオブジェクトIDが変数Aに代入されます。
B = A
の動作を説明します。
右辺の変数Aに代入されてるオブジェクトが取り出され、そのオブジェクトIDが左辺の変数Bに代入されます。
変数Aと変数Bは同じオブジェクトIDを保持することになり、ひとつのオブジェクトを共有します。
A = 2
で新たに数値2のオブジェクトが生成され、変数Aは変数Bとは異なる数値2のオブジェクトIDを保持します。
print(A) # 2
print(B) # 1
注意
上の式の A = 2
は、変数Aに代入されている数値1の内容を数値2に変更する動作だと誤解する人がいます。
A = 2
はただ単に変数Aに数値2のオブジェクトIDが代入され、変数Bとは違うオブジェクトIDになり、オブジェクトを共有しなくなります。
リストオブジェクト
A = [1,2,3] # 変数Aにリスト[1,2,3]のオブジェクトIDが代入されます。
B = A # 変数Bに変数AのオブジェクトIDが代入され、リスト[1,2,3]を共有します。
A[1] = 4 # 変数Aのリストの1番目に4を代入します。
この段階では変数Aと変数Bは同じオブジェクトを共有しています。
なので変数Bも変数Aと同じ内容になります。
print(A) # [1,4,3]
print(B) # [1,4,3]
注意
代入文
A = 1
と
A[0] = 1
は動作が異なります。
A = 1
は変数AにオブジェクトIDが代入されます。
A[0] = 1
は変数Aに代入されているリストを取り出し、リスト内部の0番要素に数値1のオブジェクトIDが代入されます。
累算代入
イミュータブルオブジェクト
A = 1
A += 1
数値などのイミュータブルオブジェクトでは、A += 1
は A = A + 1
と同じです。
A
の値を + 1
して新しく生成された数値2のオブジェクトIDを A
に代入します。
A
に代入されている数値1はイミュータブルオブジェクトで、オブジェクト内の値を2に変更することができないため、数値2を生成してそれまでとは異なるオブジェクトIDが変数Aに代入されます。
ミュータブルオブジェクト
A = [1, 2, 3]
A += [4]
A += [4]
は A.__iadd__([4])
と同じです。
リストなどのミュータブルオブジェクトには __iadd__
などの累算代入メソッドがあります。
変数A
に代入されているオブジェクトを取り出し、オブジェクトの__iadd__
メソッドを呼び出します。
リストの__iadd__
メソッドではリスト自身にデータを追加します。新しいリストを生成しないため、共有している変数のオブジェクトも変更されることになります。
数値などのイミュータブルオブジェクトには累算代入メソッドがないため、A += 1
は A = A + 1
と解釈されます。
まとめ
以上、Pythonの変数と代入について説明しました。
おまけ
Pythonはオブジェクトを実行時に生成します。
しかし、-5
~256
までの整数値はよく使われるので、毎回オブジェクトを生成しなくて済むように起動時に生成しておいて共有・再利用します。
なので
A = 1
B = 2
A += 1
の場合、通常は A += 1
で新たな数値2が生成され、Bとは違うオブジェクトIDになるはずですが、
print(id(A)) -> 140725856258520
print(id(B)) -> 140725856258520
のように同じオブジェクトIDになります。