Python変数付与時の参照伝達問題
9074 ワード
Python言語では、オブジェクトは参照によって伝達されます.値を割り当てると、オブジェクトが新しく作成された場合でも、既存のオブジェクトでも、オブジェクトの参照(値ではない)が変数に割り当てられます.
Pythonは、メモリ内のオブジェクトを追跡するために参照カウントという簡単な技術を使用しています.つまりPythonの内部には,すべての使用中のオブジェクトがどれだけの参照を持っているかが記録されている.参照カウンタと呼ばれる内部追跡変数.各オブジェクトにはそれぞれ何個の参照があり、参照カウントと略称されます.オブジェクトが作成されると、リファレンスカウントが作成され、そのオブジェクトが不要になった場合、すなわち、このオブジェクトのリファレンスカウントが0になった場合、ゴミ回収されます.
オブジェクトが作成され、変数に値が割り当てられた場合、そのオブジェクトの参照数は1に設定されます.同じオブジェクト(の参照)が他の変数に割り当てられた場合、またはパラメータとして関数、メソッド、クラスインスタンスに渡された場合、またはウィンドウオブジェクトのメンバーに割り当てられた場合、オブジェクトの新しい参照、または別名と呼ばれ、作成されます(オブジェクトの参照カウントは自動的に1が加算されます).
オブジェクトのリファレンスが破棄されると、リファレンス数が減少します.最も明らかな例は、参照がその役割範囲から離れると、関数の実行が終了すると、すべてのローカル変数が自動的に破棄され、オブジェクトの参照カウントが減少することが最もよくあります.変数が別のオブジェクトに割り当てられると、元のオブジェクトの参照カウントも自動的に1減少します.オブジェクトの参照カウントが減少する他の方法は、
del
文を使用して変数を削除するか、オブジェクトがウィンドウオブジェクトから移動された場合(または、コンテナオブジェクト自体の参照カウントが0になった場合)を含む.>>> a = 1
>>> b = a
>>> id(a), id(b)
(1386769424, 1386769424)
>>> a = 2
>>> a, b
(2, 1)
>>> id(a), id(b)
(1386769456, 1386769424)
上記の例では、
a = 1
使変数a
は整数オブジェクト1
を指し、b = a
使変数b
も整数オブジェクト1
を指し、文id(a), id(b)
から変数a
と変数b
が指すメモリアドレスが同じであることがわかる.文
a = 2
は、新しいオブジェクト2
を変数a
に割り当て、このとき変数a
はオブジェクト2
を指し、変数b
は元のオブジェクト1
を指す.文id(a), id(b)
によって、変数a
と変数b
が指すメモリアドレスが異なることがわかります.可変オブジェクトと非可変オブジェクト
Python言語のオブジェクトは、可変オブジェクトと可変オブジェクトに分けられます.
数値、文字列、およびメタグループは可変タイプであり、リストおよび辞書は可変タイプである.
>>> a = 1
>>> id(a)
1386769424
>>> a = a + 1
>>> a
2
>>> id(a)
1386769456
上記の例では、文
a = a + 1
が変数a
の値を変更した場合、変数a
が指すオブジェクト1
は可変オブジェクトであるため、新しいオブジェクト2
が作成され、変数a
がオブジェクト2
を指すようになった.>>> a = (1, 2, 3)
>>> id(a)
305934860864
>>> a = a + (4, 5, 6)
>>> a
(1, 2, 3, 4, 5, 6)
>>> id(a)
305934762152
メタグループを使用した結果は、整数オブジェクトと同じであることがわかります.
>>> a = [1, 2, 3]
>>> b = a
>>> id(a), id(b)
(305934751624, 305934751624)
>>> b += [4, 5, 6]
>>> a, b
([1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5, 6])
>>> id(a), id(b)
(305934751624, 305934751624)
上記は可変オブジェクトの一例であり、変数
a
と変数b
は同時にリストオブジェクト[1, 2, 3]
を指し、文b += [4, 5, 6]
が変数b
の値を変更すると、新しいリストオブジェクトは作成されず、元の変数a
と変数b
が指すリストオブジェクトが直接変更される.Pythonでは
a += b
とa = a + b
に違いがあります.a += b
変数a
を直接操作すると、変数a
の値が変更されます.a = a + b
では、a + b
は新しいオブジェクトを生成し、変数a
はこの新しいオブジェクトを指します.>>> a = [1, 2, 3]
>>> b = a
>>> id(a), id(b)
(305934751176, 305934751176)
>>> b = b + [4, 5, 6]
>>> a, b
([1, 2, 3], [1, 2, 3, 4, 5, 6])
>>> id(a), id(b)
(305934751176, 305939124168)
Pythonメモリ割り当て
Pythonでは、表示されるオブジェクトごとにメモリが割り当てられます.値が完全に等しい場合でも(同じかどうかは注意してください).
a = 2.0
を実行すると、b = 2.0
の2つの文は、2.0
というFloat
タイプのオブジェクトにメモリを割り当て、a
とb
をそれぞれ2つのオブジェクトに割り当てます.したがって、a
とb
は同じオブジェクトを指していません.>>> a = 2.0
>>> b = 2.0
>>> a is b
False
>>> a == b
True
ただし、メモリの使用効率を向上させるために、数値の小さい
int
オブジェクトのような簡単なオブジェクトについては、Pythonはa = 2
を実行するなど、オブジェクトメモリを再利用する方法を採用している.b = 2
を実行する場合、2
は単純なint
タイプとして数値が小さいため、Pythonはメモリを2回割り当てるのではなく、1回だけ割り当てる.次に、a
とb
を同時に割り当てられたオブジェクトに指定します.>>> a = 2
>>> b = 2
>>> a is b
True
2
ではなく大きな数値を付与すると、前のものと同じになります.>>> a = 5555
>>> b = 5555
>>> a is b
False
>>> id(a)
12464372
>>> id(b)
12464396
2つのオブジェクトは、値が等しくても異なるオブジェクトです.
>>> id(12345)
305935347440
>>> id(12345)
305935347152
参考文献[1]Pythonコアプログラミング(第2版)[2]https://www.cnblogs.com/sun-haiyu/p/7096918.html [3] https://blog.csdn.net/weixin_36250487/article/details/79620874