0

不変オブジェクトに関する記事があります。

それはいつ言うか:
variable = immutable
変数に不変を割り当てるように。

たとえば
a = b # b is a immutable
、この場合aは、a copy of bではなく、を参照していると表示されreference to bます。bがの場合mutableaa reference to b

それで:

a = 10
b = a
a =20
print (b) #b still is 10

しかしこの場合:

a = 10
b = 10
a is b # return True
print id(10)
print id(a)
print id(b) # id(a) == id(b) == id(10)

aのコピーであり10bのコピーでもある場合10、なぜid(a) == id(b) == id(10)?

4

3 に答える 3

6

「単純な」不変リテラル (特に -1 から 255 までの整数) はインターンされます。つまり、異なる名前にバインドされていても、それらは同じオブジェクトのままです。

>>> a = 'foo'
>>> b = 'foo'
>>> a is b
True
于 2012-04-14T04:48:26.100 に答える
5

その記事は一部の言語では正しいかもしれませんが、Python では間違っています。

Python で通常の割り当てを行う場合:

some_name = some_name_or_object

あなたは何もコピーしていません。割り当ての右側にあるオブジェクトの名前を指しているだけです。

可変性は無関係です。

より具体的には、理由は次のとおりです。

a = 10
b = 10
a is b

is True10is it is interned - つまり、Python は 1 つ10をメモリに保持し、 に設定されているものはすべて10同じ を指し10ます。

もしあなたがそうするなら

a = object()
b = object()
a is b

が得られますがFalse

a = object()
b = a
a is b

まだありますTrue

于 2012-04-14T04:46:52.590 に答える
2

インターンについてはすでに説明したので、可変/不変のものだけを扱います。

イミュータブルを変数に代入します。

実際に起こっていることについて話すとき、私はこの言葉遣いを選びません。

オブジェクト (メモリに存在するもの) と、それらのオブジェクトにアクセスする手段があります: 名前 (または変数)。これらは参照内のオブジェクトに「バインド」されています。(オブジェクトのポイントを言うことができます)

名前/変数は互いに独立しており、たまたま同じオブジェクトにバインドされることも、異なるオブジェクトにバインドされることもあります。そのような変数の 1 つを再配置しても、他の変数には影響しません。

値渡しや参照渡しというものはありません。Python では、常に「オブジェクトごと」に渡したり割り当てたりします。変数を関数に割り当てたり渡したりするとき、Python はコピーを作成することはなく、常に、既に持っているものとまったく同じオブジェクトを渡したり割り当てたりします。

さて、不変オブジェクトを変更しようとするとどうなるでしょうか? 既に述べたように、オブジェクトは不変であるため、代わりに次のようになります: Python は変更されたコピーを作成します。

あなたの例については:

a = 10
b = a
a =20
print (b) #b still is 10

これは可変性とは関係ありません。最初の行で、int オブジェクトを値とともに10name にバインドしますa。2 行目では、 によって参照されるオブジェクトをanameにバインドしますb

3 行目では、int オブジェクトを値とともに20nameaにバインドしますが、名前のバインド先は変更されませんb!

この場合、a は b への参照ではなく、b のコピーを参照します。b が変更可能な場合、a は b への参照になります

既に述べたように、 Python には参照のようなものはありません。Python の名前はオブジェクトにバインドされています。異なる名前 (または変数) をまったく同じオブジェクトにバインドできますが、異なる名前自体の間には関係がありません。物事を変更すると、オブジェクトが変更されます。そのため、そのオブジェクトにバインドされている他のすべての名前は「変更を確認」されます。変更したのと同じオブジェクトにバインドされていますよね?

名前を別のオブジェクトにバインドすると、それが起こります。他の名前には魔法はかけられていません。そのままの状態のままです。

リストの例については:

In [1]: smalllist = [0, 1, 2] 
In [2]: biglist = [smalllist]    
In [3]: biglist
Out[3]: [[0, 1, 2]] 

In[1] と In[2] の代わりに、次のように書いたかもしれません。

In [1]: biglist = [[0, 1, 2]]
In [2]: smalllist = biglist[0]

これは同等です。

ここで重要なことは、biglist が 1 つの項目を持つリストであることです。この一品はもちろんオブジェ。それがリストであるという事実は、何らかの魔法を思い起こさせるものではありません。たまたまリストになっている単純なオブジェクトに名前を付けただけsmalllistです。

したがって、biglist[i] へのアクセスは、smalllist へのアクセスとまったく同じです。これらは同じオブジェクトだからです。コピーは作成せず、オブジェクトを渡しました。

In [14]: smalllist is biglist[0]
Out[14]: True

リストは可変であるため、smallist を変更して、その変更が biglist に反映されるのを確認できます。なんで?smallist が参照するオブジェクトを実際に変更したためです。まだ同じオブジェクトがあります (変更されているという事実は別として)。しかし、biglist は最初の項目として同じオブジェクトを参照するため、その変更を「認識」します。

In [4]: smalllist[0] = 3
In [5]: biglist
Out[5]: [[3, 1, 2]]

リストを「倍増」する場合も同様です。

In [11]: biglist *= 2
In [12]: biglist
Out[12]: [[0, 1, 2], [0, 1, 2]]

何が起こるか: リストがあります: [object1, object2, object3] (これは一般的な例です) 得られるもの: [object1, object2, object3, object1, object2, object3 ] : "biglist") リストの末尾にあるすべてのアイテム。繰り返しますが、オブジェクトを挿入しますが、魔法のようにコピーを作成するわけではありません。

したがって、biglist の最初の項目内の項目を変更すると、次のようになります。

In [20]: biglist[0][0]=3
In [21]: biglist
Out[21]: [[3, 1, 2], [3, 1, 2]]

smalllistすべての意図と目的のために、次のbiglistように表すことができるため、を変更することもできます。 [smalllist, smalllist]-- まったく同じオブジェクトが 2 回含まれています。

于 2012-04-14T09:07:20.450 に答える