Pythonは複数の変数を同じ値に割り当てていますか?リストの動作


131

変数を初期化するために以下に示すように複数の割り当てを使用しようとしましたが、動作に混乱しました。値のリストを個別に再割り当てすることを期待しています。

a=b=c=[0,3,5]
a[0]=1
print(a)
print(b)
print(c)

結果は次のとおりです:[1、3、5] [1、3、5] [1、3、5]

あれは正しいですか?複数割り当てには何を使用すればよいですか?これと何が違うの?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

結果:( 'f:'、3)( 'e:'、4)


2
あなたがしたいですかabc,(この場合はリスト)と同じ値にすべてのポイントに、またはあなたがしたいですかa=0b=3c=5。その場合、あなたは欲しいa,b,c = [0,3,5]か、単にa,b,c = 0,3,5
chepner 2013年

回答:


271

C / Java /その他の言語からPythonにアクセスする場合。家族、それはあなたがa「変数」として考えるのをやめ、それを「名前」として考えるのを始めるのを助けるかもしれません。

ab、とc等しい値を持つ異なる変数ではありません。それらは同じ同一の値に対して異なる名前です。変数には、タイプ、ID、アドレス、およびそのようなあらゆる種類のものがあります。

名前にはそれがありません。もちろんはあり、同じ値に多くの名前を付けることができます。

Notorious B.I.G.ホットドッグ* を与えて、ホットドッグBiggie SmallsChris Wallace持っている場合。の最初の要素aを1に変更するbと、およびの最初の要素cは1になります。

2つの名前が同じオブジェクトの名前であるかどうかを知りたい場合は、is演算子を使用します。

>>> a=b=c=[0,3,5]
>>> a is b
True

次に尋ねます:

これと何が違うの?

d=e=f=3
e=4
print('f:',f)
print('e:',e)

ここでは、名前eを値に再バインドしています4。これは、名前には影響しませんdし、fどのような方法インチ

以前のバージョンではa[0]、ではなくに割り当てていましたa。つまり、の観点からa[0]はを再バインドしていますa[0]が、の観点からはaインプレースで変更しています。

このid関数を使用すると、オブジェクトのIDを表す一意の番号isが得られ、助けにならない場合でも、どのオブジェクトであるかを正確に確認できます。

>>> a=b=c=[0,3,5]
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261120
>>> id(b[0])
4297261120

>>> a[0] = 1
>>> id(a)
4473392520
>>> id(b)
4473392520
>>> id(a[0])
4297261216
>>> id(b[0])
4297261216

a[0]が4297261120から4297261216に変更されていることに注意してください。これは、別の値の名前になっています。そしてb[0]今では、同じ新しい値の名前にもなっています。だabまだ同じオブジェクトを命名しています。


内部では、a[0]=1実際にリストオブジェクトのメソッドを呼び出しています。(これはと同等a.__setitem__(0, 1)です。)したがって、実際には何も再バインドしていませ。を呼び出すようなものmy_object.set_something(1)です。確かに、オブジェクトがこのメソッドを実装するためにインスタンス属性を再バインドしている可能性がありますが、それは重要ではありません。重要なのは、何も割り当てず、オブジェクトを変更することだけです。そして、それはと同じa[0]=1です。


user570826が尋ねた:

もし私たちが持っているとしたら、 a = b = c = 10

これはまったく同じ状況a = b = c = [1, 2, 3]です。同じ値に3つの名前があります。

ただし、この場合、値はintで、intsは不変です。どちらの場合も、あなたは再バインドすることができますa(例えば、異なる値にa = "Now I'm a string!")が、元の値には影響しません、これbcはまだの名前になります。違いはリストで、あなたが値を変更することができるということである[1, 2, 3][1, 2, 3, 4]行うことによって、例えば、a.append(4); そのため、実際にその値を変更することだbc、のための名前であるb今、bのだろう[1, 2, 3, 4]。値10を他の値に変更する方法はありません。10クラウディアと同様に、吸血鬼は永遠に5です(少なくとも彼女がキルスティンダンストに置き換えられるまで)。


*警告:Notorious BIGにホットドッグを与えないでください。ギャングスタラップゾンビは、深夜以降は餌を与えないでください。


もし私たちhave, a = b = c = 10;がbの値を更新しようとすると、それは他の何かに影響しますか?私は彼らのIDが同じであることを確認しましたが?
AJ

@ user570826:10不変です。つまり、値を更新する方法がないため、質問は意味がありません。b別の値をポイントすることもできますが、そうしても、元の値をポイントしているaおよびcには影響しません。リストの違いは、それらが変更可能であることです。たとえば、appendリストやlst[0] = 3に変更できます。これにより、値が更新され、その値のすべての名前で表示されます。
abarnert 2014

72

咳咳

>>> a,b,c = (1,2,3)
>>> a
1
>>> b
2
>>> c
3
>>> a,b,c = ({'test':'a'},{'test':'b'},{'test':'c'})
>>> a
{'test': 'a'}
>>> b
{'test': 'b'}
>>> c
{'test': 'c'}
>>> 

10
私見、これは実際に私が多重割り当てに何を使うべきかというOPの最初の重要な質問に答えますが、上記のより高い評価とより脳の答えは答えません。
ウィル・クロックスフォード、

2
またはa,b,c = 1,2,3、ブラケットがなくてもPython 2または3で機能します。
ウィルクロックスフォード、

14

はい、それは予想される動作です。a、b、cはすべて同じリストのラベルとして設定されます。3つの異なるリストが必要な場合は、それらを個別に割り当てる必要があります。明示的なリストを繰り返すか、リストをコピーする多くの方法のいずれかを使用できます。

b = a[:] # this does a shallow copy, which is good enough for this case
import copy
c = copy.deepcopy(a) # this does a deep copy, which matters if the list contains mutable objects

Pythonの代入ステートメントはオブジェクトをコピーしません-それらは名前をオブジェクトにバインドし、オブジェクトは設定した数のラベルを持つことができます。最初の編集でa [0]を変更すると、a、b、cがすべて参照する単一のリストの1つの要素が更新されます。2番目のeの変更では、eを別のオブジェクトのラベルに切り替えます(3ではなく4)。


13

Pythonでは、すべてがオブジェクトであり、「単純な」変数タイプ(int、floatなど)でもあります。

変数の値を変更すると、実際にはそのポインターが変更されます。2つの変数を比較すると、それらのポインターが比較されます。(明確にするために、ポインターは、変数が格納されている物理コンピューターメモリ内のアドレスです)。

その結果、内部変数の値を変更すると、メモリ内の値が変更され、このアドレスを指すすべての変数に影響します。

あなたの例では、あなたがするとき:

a = b =  5 

これは、aとbが値5を含むメモリ内の同じアドレスを指していることを意味します。

a = 6

aは6を含む別のメモリロケーションを指し、bは5を含むメモリアドレスを指すため、bには影響しません。

しかし、あなたがするとき:

a = b = [1,2,3]

aとbも同じ場所を指していますが、違いは、リストの値の1つを変更した場合です。

a[0] = 2

これは、aが指すメモリの値を変更しますが、aは引き続きbと同じアドレスを指しているため、bも変更されます。


6
これは非常に誤解を招くものです。ポインターは確かにPythonレベルでは表示されず、4つの主要な実装(PyPyとJython)のうち少なくとも2つは実装内でも使用しません。
abarnert 2013年

1
Pythonの内部を読んで探索することを歓迎します。Pythonのすべての変数が実際にはポインターであることを発見します。
Ori Seri 2013年

4
いいえ。Python(CPython)の1つの実装では、すべての変数がへのポインタPyObjectです。これは、PyPyやJythonなどの他の実装では当てはまりません。(実際、それらの実装が記述されている言語にはポインターさえないため、それどのように真実であるかさえも明確ではありません。)
abarnert

概念的な意味での「ポインタ」の使用は問題ないと思います(おそらく実装が異なる場合があるという免責事項がある場合)。特に、動作を伝えることが目的である場合はそうです。
レボン

@abarnert人々がPythonを言うとき、それらはCPythonを意味します。人々がクリーネックスを言うときのように、彼らは顔のティッシュを意味します。これらのコメントでセマンティクスゲームをプレイすることは本当に不要です。彼が書いたものに関して、彼が述べたものの行動は間違っていますか?
4

10

を使用id(name)して、2つの名前が同じオブジェクトを表すかどうかを確認できます。

>>> a = b = c = [0, 3, 5]
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488

リストは変更可能です。つまり、新しいオブジェクトを作成しなくても、値を変更できます。ただし、値の変更方法によって異なります。

>>> a[0] = 1
>>> print(id(a), id(b), id(c))
46268488 46268488 46268488
>>> print(a, b, c)
[1, 3, 5] [1, 3, 5] [1, 3, 5]

新しいリストをに割り当てると、aそのIDが変更されるため、bおよびcの値には影響しません。

>>> a = [1, 8, 5]
>>> print(id(a), id(b), id(c))
139423880 46268488 46268488
>>> print(a, b, c)
[1, 8, 5] [1, 3, 5] [1, 3, 5]

整数は不変なので、新しいオブジェクトを作成しないと値を変更できません。

>>> x = y = z = 1
>>> print(id(x), id(y), id(z))
507081216 507081216 507081216
>>> x = 2
>>> print(id(x), id(y), id(z))
507081248 507081216 507081216
>>> print(x, y, z)
2 1 1

1
idは必ずしもメモリの場所ではありません。ドキュメントは言う、これは「このオブジェクトの有効期間は一意かつ一定であることが保証されているアイデンティティ...整数を...。」を返します CPythonはメモリアドレスをとして使用しますidが、他のPython実装では使用しない場合があります。たとえば、PyPyはそうではありません。また、「2つの変数が同じメモリ位置を指す」と言っても、それをCスタイルで理解している人には誤解を招く恐れがあります。「同じオブジェクトの2つの名前」の方が正確であり、誤解を招きにくい。
abarnert 2013年

明確化のための@abarnertありがとう、私は答えを更新しました。
jurgenreza 2013年

7

最初の例では、a = b = c = [1, 2, 3]あなたは本当に言っています:

 'a' is the same as 'b', is the same as 'c' and they are all [1, 2, 3]

「a」を1に、「b」を「2」に、「c」を3に設定する場合は、次のようにしてください。

a, b, c = [1, 2, 3]

print(a)
--> 1
print(b)
--> 2
print(c)
--> 3

お役に立てれば!


4

簡単に言えば、最初のケースでは、複数の名前を listます。リストのコピーはメモリに1つだけ作成され、すべての名前はその場所を参照します。したがって、任意の名前を使用してリストを変更すると、実際にはメモリ内のリストが変更されます。

2番目のケースでは、同じ値の複数のコピーがメモリに作成されます。したがって、各コピーは互いに独立しています。


3

あなたが必要なのはこれです:

a, b, c = [0,3,5] # Unpack the list, now a, b, and c are ints
a = 1             # `a` did equal 0, not [0,3,5]
print(a)
print(b)
print(c)

3

私が必要とすることを行うコードは次のようになります:

# test

aux=[[0 for n in range(3)] for i in range(4)]
print('aux:',aux)

# initialization

a,b,c,d=[[0 for n in range(3)] for i in range(4)]

# changing values

a[0]=1
d[2]=5
print('a:',a)
print('b:',b)
print('c:',c)
print('d:',d)

結果:

('aux:', [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]])
('a:', [1, 0, 0])
('b:', [0, 0, 0])
('c:', [0, 0, 0])
('d:', [0, 0, 5])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.