web-dev-qa-db-ja.com

参照によるPythonの受け渡し

こんにちは私はPythonの参照渡しがどのように機能するかを理解しようとしています。私は例を持っています:

>>>a = 1
>>>b = 1
>>>id(a);id(b)
140522779858088
140522779858088

Aとbはどちらも、同一性を持つのと同じ値を参照しているため、これは完全に理にかなっています。私がよく理解していないのは、この例がどのようになっているのかです。

>>>a = 4.4
>>>b = 1.0+3.4
>>>id(a);id(b)
140522778796184
140522778796136

この例とは異なります。

>>>a = 2
>>>b = 2 + 0
>>>id(a);id(b)
140522779858064
140522779858064

3番目の例では、0 intオブジェクトがインタープリターによって「なし」と見なされており、変数「a」が参照しているオブジェクトとは異なるIDが必要であると認識されていないためですか(2)。 2番目の例では、「b」は2つの異なるintオブジェクトを追加し、インタプリタは追加する両方のオブジェクトにメモリを割り当てています。これにより、変数「a」は変数「b」とは異なるIDになります。

27
Pulse

最初の例では、interningのため、名前abは両方とも同じオブジェクトを「参照」しています。割り当てステートメントは、メモリ内でたまたまぶら下がっていた既存のオブジェクトを再利用したという理由だけで、同じidの整数になりました。これは整数の信頼できる動作ではありません。

>>> a = 257
>>> b = 257
>>> id(a), id(b)
(30610608, 30610728)

上で示したように、十分に大きい整数を選択すると、2番目の例のfloatが動作したように動作します。そして、小さな整数のインターンは、Python言語ではoptionalですが、これはたまたまCPython実装の詳細です:それは新しいオブジェクトを作成するオーバーヘッドを回避することを目的としたパフォーマンスの最適化。Pythonインタープリターのメモリフットプリントが高くなる代わりに、一般的に使用される整数インスタンスをキャッシュすることで処理を高速化できます。

Pythonを扱うときは、「参照」と「値」について考えないでください。Cで機能するモデルは、ここでは実際にはうまく機能しません。代わりに、「名前」と「オブジェクト」について考えてください。

names

上の図は、3番目の例を示しています。 2はオブジェクト、abは名前です。同じオブジェクトを指す異なる名前を持つことができます。また、オブジェクトは名前なしで存在できます。

割り当て変数のみ名札を付けます。そして削除変数のみ名札を削除。この考えを念頭に置いておくと、Pythonオブジェクトモデルは二度とあなたを驚かせることはありません。

49
wim

述べたように ここ 、CPythonは-5から256までの整数をキャッシュします。したがって、同じ値を持つこの範囲内のすべての変数は同じIDを共有します(ただし、将来のバージョンではそれに賭けませんが、それは現在の実装)

可能な値の「無限大」があるため(無限ではないが、浮動小数点のために大きい)、浮動小数点数にはそのようなことはないので、異なる方法で同じ値を計算する可能性は整数に比べて非常に低いです。

>>> a=4.0
>>> b=4.0
>>> a is b
False

Python変数は常にオブジェクトへの参照です。これらのオブジェクトは、可変オブジェクトと不変オブジェクトに分けることができます。

可変型はIDを変更せずに変更できるため、このオブジェクトを指すすべての変数が更新されます。ただし、不変オブジェクトはこの方法で変更できないため、Pythonは変更を含む新しいオブジェクトを生成し、この新しいオブジェクトを指すように変数を再割り当てします。したがって、変更前の変数のIDです。変更後の変数のIDとは一致しません。

整数と浮動小数点数は不変であるため、変更後は別のオブジェクトを指し、したがって異なるIDを持ちます。

問題は、CPythonがいくつかの一般的な整数値を「キャッシュ」して、メモリを節約するために同じ値を持つ複数のオブジェクトが存在しないことです。2はキャッシュされた整数の1つであるため、変数が整数2を指すたびにIDは同じになります(値はpython実行ごとに異なります)。

3
Adirio