これは一般的にほとんどの言語に当てはまるかもしれませんが、よくわかりません。私は Python の初心者で、常に C# と VB でリストのコピーを作成してきました。しかし、Python では、リストを引数として渡し、「for i in range」を使用して列挙し、リスト引数の値を変更すると、入力値によって元のリストが実際に変更されます。Python はデフォルトで引数を値で渡すことになっているので、関数が終了しても、関数を呼び出す前の元の値が残っていると思いました。私は何が欠けていますか?ありがとう!
3 に答える
Python は引数を値で渡しますが、受け取る値は参照のコピーです (ちなみに、これは C#、VB.NET、および Java の動作とまったく同じです)。
これは覚えておくべき重要なことです:
オブジェクトは参照によって渡されません。オブジェクト参照は値によって渡されます。
参照のコピーがあるため、その参照が指すものに対する操作は、元の参照自体を保持しているかのようになります。
Python -- Java がプリミティブ スカラー以外に対して行うように、また C# や VB.NET がボックス化された型や out / ref parms とは対照的にデフォルトの kind パラメータに対して行うように -- 「オブジェクト参照によって」渡します (ここでそのフレーズを検索してください)。 -- これは、Python のアーキテクトであり作成者である Guido が、この引数渡しの概念を説明するために使用する方法です)。
すべての名前は、何らかのオブジェクトへの参照です。名前 (またはその他の式) を引数として渡すと、同じオブジェクトへの別の参照が作成されます (関数本体はパラメーターの名前を介してアクセスできます)。((「名前への参照」などというものはありません。オブジェクトへの参照の一種である名前とオブジェクト -- ピリオドがあります))。
変更可能なオブジェクト、つまり変更メソッド (リストなど) を持つオブジェクトを渡す場合、呼び出された関数は、その変更メソッドを直接的または間接的に呼び出すことで、オブジェクトを変更できます。((「間接的に」とは、「演算子を介して」という意味です。例:
somelist[len(somelist):] = [whatever]
とまったく同じですsomelist.append(whatever)
。))
リストを関数に渡したいが、関数がそのリストを何らかの方法で変更できるようにしたくない場合は、元のリストではなくリストのコピーを渡す必要があります-Java、C#、VB のように。ネット。
名前の再バインドとオブジェクトの変更の違いを明確にしてください。名前の再バインド (「barename」、つまり -- 修飾名は異なります;-)はその名前にのみ影響し、オブジェクトにはまったく影響しません。例えば:
def f1(alist):
alist = [23]
def f2(alist):
alist[:] = [23]
これら 2 つの機能の違いがわかりますか? 1 つは、barename alist
を再バインドすることです。何にも何の影響もありません。もう 1 つは、引数として受け取ったリスト オブジェクトを変更 (変更、変更、...) することです。その内容を、唯一の項目として int を持つ 1 つの項目のリストに設定します。 全然、全然違う!!!
Andrewの回答に追加するには、元のリストを保持する場合は、リストのコピーを明示的に作成する必要があります。モジュールを使用してこれをcopy
行うか、次のようなことを行うことができます
a = [1,2]
b = list(a)
オブジェクトのコピーは通常、パフォーマンスの低下を意味するため、大規模なプロジェクトでコピーモジュールを明示的に使用すると便利です。そうすれば、より多くのメモリを使用するすべての場所を簡単に見つけることができます。