Python では変数は「ストレージではなく名前」であり、変数をストレージのように考えないことが重要であると聞いたり読んだりしたことがありますが、それが重要である理由を示す例は 1 つも見つかりませんでした。問題は、名前である変数とストレージである変数を区別することがなぜ重要なのかということです。
3 に答える
a = SomeObject()
b = a
名前がストレージである場合 (たとえば、C や C++ のように)、 と の両方a
にb
文字通りそれぞれオブジェクトが含まれます。
a +---------+
| value 1 |
+---------+
b +---------+
| value 2 |
+---------+
たとえば、a.x = ...
は値 1 で動作し、値 2 はまったく関係ありません。ある値を別の値で操作できるようにする値を提供する言語に注意してください (例: ポインター)。ただし、これはこのトピックとは無関係であり、代わりに Python のモデルで同様のことを行うことができます。
Python および同様の言語では、メモリは次のようになります。
a +-------------+
| reference 1 | ---------+
+-------------+ v
+---------+
| value 1 |
+---------+
b +-------------+ ^
| reference 2 | ---------+
+-------------+
ここでの参照は、オブジェクトを参照する (当たり前!) 架空のトークンです。任意のオブジェクトへの参照がいくつあってもかまいません。オブジェクトはそれらのいずれも認識しません。オブジェクトへの参照がない場合でも、オブジェクトは残り続ける可能性があります。また、参照がポップアップする場所は変数だけではないことに注意してください。リストには参照が含まれ、辞書には参照が含まれ、オブジェクトの属性には参照が含まれます。オブジェクトは言うまでもなく、言語では (したがって、ポインター演算に相当するものもありません)。
最も目に見える結果は、変数が別名になる可能性があることです。そのためvalue #1
、一方を介した変更は他方を介して表示されます。
a.something = 1
b.something = 2
assert a.something == 2
変数の再代入は値 1 の変更ではありませんが、参照を変更するだけです。つまり、a = ...
影響を与えずb
、その逆も同様です。
変数がデータを「含む」Cとは異なります。
Python では、名前はデータが保存されている場所への参照です。
だから、リスト(可変)で
>>> x = [10]
>>> y = x
>>> id(x) == id(y) # they refer to the same object
True
>>> y.append(1) # manipulate y
>>> x # x is manipulated
[10, 1]
>>> y # and so is y.
[10, 1]
そして文字列付き(不変)
>>> x = '10'
>>> y = x
>>> id(x) == id(y)
True
>>> y += '1' # manipulate y
>>> id(x) == id(y) # the ids are no longer equal
False
>>> x # x != y
'10'
>>> y
'101'
変数の場合del
はオブジェクトへの参照を削除し、オブジェクトの参照が 0 の場合はガベージ コレクションされます。
この種のものは、通常、ボックスと矢印を描くことで説明されます。
子:
pos = { .x = 1, .y = 2 }
------- -----------
| pos |----------->| x:1 y:2 |
------- -----------
pos2 = pos
------- -----------
| pos |----------->| x:1 y:2 |
------- -----------
------- -----------
| pos2|----------->| x:1 y:2 |
------- -----------
pos2.x = 9
------- -----------
| pos |----------->| x:1 y:2 |
------- -----------
------- -----------
| pos2|----------->| x:9 y:2 |
------- -----------
パイソン:
pos = { 'x':1, 'y': 2 }
------- ----------- -----------
| pos |----------->| 0xabcde |------->| x:1 y:2 |
------- ----------- -----------
pos2 = pos
------- -----------
| pos |----------->| 0xabcde |--\
------- ----------- | -----------
|---->| x:1 y:2 |
------- ----------- | -----------
| pos2|----------->| 0xabcde |--/
------- -----------
pos2.x = 9
------- -----------
| pos |----------->| 0xabcde |--\
------- ----------- | -----------
|---->| x:9 y:2 |
------- ----------- | -----------
| pos2|----------->| 0xabcde |--/
------- -----------
つまり、python 変数は基本的にポインタです。それらには「値」は含まれませんが、値のアドレスが含まれます。ある変数を別の変数に代入すると、アドレスだけがコピーされます。変数を変更すると、実際にはその基になる値が変更されます。
@delnan の絵の方が優れていますが (?)、重要な点が抜けています。
Python の変数は抽象的な「名前」ではありません。それらには値があり、これらの値は神秘的な「参照」ではなく、かなり具体的なメモリアドレスです。変数への各アクセスには、二重間接参照が含まれます。最初に、変数の値 (アドレス) を取得し、次に、このアドレスに「住んでいる」人を調べます。
この点で python はユニークではないことに注意してください。他の「スクリプト」言語は同様の仕組みを使用しています。