免責事項:私はPythonを使用していないので、私が言ういくつかのことが間違っている可能性があります。Pythonの専門家、お気軽に訂正してください。
素晴らしい質問です。私はあなたが質問をするように促す中心的な誤解(私がそれをそれと呼ぶことさえできないならば;あなたがあなたが使用した思考プロセスに到達した方法は完全に合理的です)はこれだと思います:
私が書くとき、それはそれがにあるという意味ではb[0] = a
ありません。それは、それが指すものを指す参照を含むことを意味します。a
b
b
a
変数a
とb
それ自体は、それ自体が「モノ」でさえありません。また、変数自体も、メモリ内の匿名の「モノ」へのポインタにすぎません。
参照の概念は、プログラミング以外の世界からの大きな飛躍であるため、これを念頭に置いてプログラムをステップスルーしてみましょう。
>>> a = [0]
たまたま何かが含まれているリストを作成します(今は無視してください)。重要なのはリストです。そのリストはメモリに保存されます。それがメモリ位置1001に格納されているとしましょう。次に、割り当てにより、プログラミング言語で後で使用できる=
変数が作成されます。a
この時点で、メモリ内にいくつかのリストオブジェクトと、その名前でアクセスできるリストオブジェクトへの参照がありますa
。
>>> b = [0]
これは、に対して同じことを行いb
ます。メモリ位置1002に格納される新しいリストがあります。プログラミング言語はb
、メモリ位置を参照し、次にリストオブジェクトを参照するために使用できる参照を作成します。
>>> a[0], b[0] = b, a
これは同じことを2つ行うので、1つに焦点を当てましょうa[0] = b
。これが行うことはかなり空想です。それは最初に等式の右側を評価し、変数を見て、それへの参照であるb
ため、メモリ内の対応するオブジェクト(メモリオブジェクト#1002)をフェッチしますb
。左側で起こることは同様に空想です。a
はリスト(メモリオブジェクト#1001)を指す変数ですが、メモリオブジェクト#1001自体には独自の参照がいくつかあります。a
使用するandのような名前を持つ参照の代わりに、これらのb
参照には。のような数値インデックスがあり0
ます。だから、今、これは何をするのですかa
インデックス付き参照の山であるメモリオブジェクト#1001をプルアップし、インデックス0の参照に移動し(以前は、この参照は実際の番号を指していました0
。これは1行目で行ったことです)、その参照を再ポイントします(つまり、メモリオブジェクト#1001)の最初で唯一の参照であり、方程式の右側にあるものが評価されます。したがって、オブジェクト#1001の0番目の参照はオブジェクト#1002を指します。
>>> a
[[[...]]]
>>> b
[[[...]]]
これは、プログラミング言語によって行われる単なる空想です。評価を依頼するとa
、メモリオブジェクト(場所#1001のリスト)が表示され、独自の魔法を使用して無限であることが検出され、そのようにレンダリングされます。
>>> a == b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: maximum recursion depth exceeded in cmp
このステートメントの失敗は、Pythonが比較を行う方法と関係があります。オブジェクトをそれ自体と比較すると、すぐにtrueと評価されます。別のオブジェクトと比較して異議を唱える場合、「魔法」を使用して、等式が真であるか偽であるかを判断します。Pythonのリストの場合、各リスト内のすべてのアイテムを調べて、それらが等しいかどうかをチェックします(次に、アイテム自体の等価性チェックメソッドを使用します)。だから、あなたがしようとするとa == b
。それが行うことは、最初にb(オブジェクト#1002)とa(オブジェクト#1001)を掘り起こし、次にそれらがメモリ内で異なるものであることに気付くので、再帰リストチェッカーに行きます。これは、2つのリストを反復処理することによって行われます。オブジェクト#1001には、オブジェクト#1002を指すインデックス0の要素が1つあります。オブジェクト#1002には、オブジェクト#1001を指すインデックス0の要素が1つあります。したがって、プログラムは、すべての参照が同じものを指している場合、オブジェクト#1001と#1002は等しいと結論付け、#1002(#1001の唯一の参照点)と#1001(#1002の唯一の参照点)が同じこと。この同等性チェックは決して止まることはありません。同じことが、止まらないリストでも起こります。同じエラーが発生する可能性がc = [0]; d = [0]; c[0] = d; d[0] = c
あります。a == c
>>> a[0] == b
True
前の段落で示唆したように、Pythonはショートカットを使用するため、これはすぐにtrueに解決されます。a[0]
オブジェクト#1002を指し、オブジェクト#1002を指すため、リストの内容を比較する必要はありませんb
。Pythonは、それらが文字通りの意味で同一であることを検出し(それらは同じ「もの」です)、内容をチェックすることさえしません。
>>> a[0][0] == b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: maximum recursion depth exceeded in cmp
a[0][0]
オブジェクト#1001を指すようになるため、これはエラーに戻ります。IDチェックは失敗し、再帰的なコンテンツチェックにフォールバックします。再帰的なコンテンツチェックは終了しません。
>>> a[0][0][0] == b
True
もう一度、a[0][0][0]
オブジェクト#1002を指しますb
。再帰チェックはスキップされ、比較はすぐにtrueを返します。
特定のコードスニペットに直接関係しない高レベルのジバージャバー:
- 他のオブジェクトを参照する参照があるので、「無限の」ネストのように見えるものがありますが、
a
(オブジェクト#1001と呼んでいるように)によって参照されるオブジェクトとb
(#1002)によって参照されるオブジェクトは両方ともメモリ内の同じサイズ。そして、それらはすべて他のそれぞれのメモリ位置を指すリストであるため、そのサイズは実際には信じられないほど小さいです。
- また、あまり「寛大でない」言語では、両方の参照がメモリ内の同じ場所を指しているという意味で、それらが指すメモリオブジェクトが同じである場合にのみ
==
、2つの参照をリターンと比較することにも注意してください。Javaはその一例です。このような言語で出現した文体の慣習は、カスタムの同等性テストを実行するために、オブジェクト自体(Javaの場合は通常呼ばれます)にメソッド/関数を定義することです。Pythonは、リストに対してこれをすぐに実行します。特にPythonについてはわかりませんが、少なくともRubyでは、実行すると、呼び出されたメソッド(上書き可能)を実際に呼び出すという意味でオーバーロードされています。理論的には、あなたが作るのを妨げるものは何もないでしょうtrue
equals()
==
someobject == otherobject
==
someobject
someobject == otherobject
ブール値以外のものを返します。