リスト、配列などのコレクションをPythonの別の関数に渡すと、そのコピーが作成されますか、それとも単なるポインターですか?
8 に答える
Pythonはオブジェクトへの参照を値で渡します。
Python はオブジェクトへの参照を (Java のように) 値で渡し、Python のすべてはオブジェクトです。これは単純に聞こえますが、一部のデータ型は値渡しの特性を示しているように見え、他のデータ型は参照渡しのように動作しているように見えることに気付くでしょう...どうしたのでしょう?
可変オブジェクトと不変オブジェクトを理解することが重要です。文字列、タプル、数値などの一部のオブジェクトは不変です。関数/メソッド内でそれらを変更すると、新しいインスタンスが作成され、関数/メソッド外の元のインスタンスは変更されません。リストや辞書などの他のオブジェクトは変更可能です。つまり、オブジェクトをその場で変更できます。したがって、関数/メソッド内のオブジェクトを変更すると、元のオブジェクトも変更されます。
つまり、参照/値の概念全体がPythonに適合しません。Pythonには変数の「値」がありません。Pythonには、オブジェクトとオブジェクトを参照する名前のみがあります。
したがって、関数を呼び出して括弧内に「名前」を入れると、次のようになります。
def func(x): # defines a function that takes an argument
... # do something here
func(myname) # calling the function
名前自体ではなく、ポイントしている実際のオブジェクトmyname
が渡されます。関数内では、渡された同じオブジェクトを参照するために別の名前( )が付けられています。 myname
x
関数内のオブジェクトが変更可能である場合は変更できますが、外部名が指しているものを変更することはできません。あなたがするときに起こるのとまったく同じです
anothername = myname
したがって、私はあなたの質問に次のように答えることができます:
これは「値渡し」ですが、すべての値はオブジェクトへの参照にすぎません。
ここでの回答は役に立ちましたが、私がカバーしていないこの細かい区別を示す必要があることがわかりました。これは、その後のCL実験で証明しました。
- 不変オブジェクトは、関数呼び出し内で変更することはできません。(これまでの回答はそれだけ言っています...)
- ただし、可変オブジェクト内に含まれる不変オブジェクトは、メソッド呼び出し内で再割り当てできます。
'num'は不変のNumberオブジェクトであるため、ここでは変更されません[私のポイント1をサポートします]:
def incr_num(num):
num += 1
num = 0
num
0
incr_num(num)
num
0
ここでの「list[0]」も不変のNumberオブジェクトです。
def incr_list(list):
list[0] += 1
list = [0]
list[0]
0
incr_list(list)
list[0]
1
では、不変のNumberオブジェクトである「list [0]」はどのように変化しましたか(私のポイント2をサポートします)、上記の例のNumberオブジェクト「num」は変化しませんでしたか? 不変のNumberオブジェクト「list[0]」は可変リストオブジェクト「list」内に含まれていますが、最初の例の「num」は含まれていないNumberオブジェクト(不変)です。
よく意図されていますが、@ Stephen Papeのトップクラスの回答(以下に引用)や他の同様の回答は完全に正しくなかったと思います(そしてそれが私にこの回答を書く動機を与えました):
文字列、タプル、数値などの一部のオブジェクトは不変です。関数/メソッド内でそれらを変更すると、新しいインスタンスが作成され、関数/メソッド外の元のインスタンスは変更されません。
上記の2番目のコード実験では、Numberオブジェクト('list [0]')がメソッド内で変更され、次に関数外の元のインスタンスが変更されています。
参照は渡されますが、パラメーターが不変オブジェクトの場合、メソッド内で変更すると新しいインスタンスが作成されます。
オブジェクトが渡されます。コピーではなく、基になるオブジェクトへの参照です。
参考までに:
>>> x = [0,1,2,3]
>>> def foo(x_list):
x_list[0] = 1
>>> foo(x)
>>> x
[1, 1, 2, 3]
謙虚な例を挙げさせてください
def swap(a, b):
x = a
print id(x)
print id(a)
print id(b)
a = b
print id(a)
b = x
print id(b)
a[0]= '20'
var1 = ['1','2','3','4']
var2 = ['5','6','7','8','9']
print id(var1)
print id(var2)
swap(var1, var2)
print id(var1)
print id(var2)
print var1
print var2
次の結果が生成されます
28329344 var1 28331264 var2 28329344 x 28329344 a 28331264 b a = b の後 28331264 a b = x 28329344 b の後 28329344 var1 28331264 var2 '6', '7', '8', '9']
メモリアドレスへのマッピング 28329344 28331264 var1 var2 ab x a=b の後 a b=x の後 b a[0] = '20' [0] = '20' の後 return ['1','2','3', '4'] ['20', '6', '7', '8', '9']