Pythonではvalues=[0,1,2];values[1]=values,なぜ結果は[0,[...],2]?

7142 ワード

http://www.zhihu.com/question/21000872/answer/16856382
>>>
values = [0, 1, 2] >>> values[1] = values >>> values [0, [...], 2]
 
[0, [0, 1, 2], 2]

Pythonは値を付けず、参照のみです.これは、自身を参照する構造を作成することに相当し、無限ループを招きます.この問題を理解するために、基本的な概念を明らかにする必要があります.Pythonには「変数」はありませんが、私たちが普段言っている変数は「ラベル」にすぎません.実行
values = [0, 1, 2]


の場合、Pythonはまずリストオブジェクト[0,1,2]を作成し、valuesというラベルを貼り付けます.後で実行すると
values = [3, 4, 5]


すると、Pythonは別のリストオブジェクトを作成し[3,4,5]、さっきのvaluesというラベルを前の[0,1,2]オブジェクトから引き裂いて、[3,4,5]というオブジェクトに貼り直します.最初から最後まで、valuesというリストオブジェクトコンテナは存在せず、Pythonはオブジェクトの値をvaluesにコピーしなかった.プロセスは図に示すように:在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?
実行
values[1] = values


の場合、Pythonが行うことは、valuesというラベルが参照するリストオブジェクトの2番目の要素をvaluesが参照するリストオブジェクト自体に指すことです.実行後、valuesラベルは元のオブジェクトを指しますが、そのオブジェクトの構造が変化し、前のリスト[0,1,2]から[0,?,2]に変わりましたが、これは?そのオブジェクト自体への参照です.図に示すように、在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?はあなたが必要とする効果を達成するには、[0,[0,1,2],2]というオブジェクトを得るには、values[1]をvaluesが参照するオブジェクト自体に直接指すのではなく、必要でしょう[0,1,2]というオブジェクトを「コピー」して、新しいオブジェクトを得て、values[1]をこのコピー後のオブジェクトに指す必要があります.Pythonではオブジェクトをコピーする操作はオブジェクトタイプによって異なりますが、コピーリストvaluesの操作は
values[:]


だから実行する必要があります
values[1] = values[:]


Pythonが行うことは、まずdereferenceがvaluesが指すオブジェクト[0,1,2]を得、その後[0,1,2][:]コピー操作を実行して新しいオブジェクトを得、内容も[0,1,2]であり、その後valuesが指すリストオブジェクトの2番目の要素をこの複制二来のリストオブジェクトに向け、最終的にvaluesが指すオブジェクトは[0,[0,1,2],2である.プロセスは図に示すように:在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?
さらに言えばvalues[:]レプリケーション操作はいわゆる「浅いレプリケーション」(shallow copy)であり、リストオブジェクトにネストがある場合にも予想外のエラーが発生します.
a = [0, [1, 2], 3]

b = a[:]

a[0] = 8

a[1][1] = 9


問:この時aとbはそれぞれいくらですか.正解はaが[8,[1,9%,3]、bが[0,[1,9%,3]である.気づいたか?bの2番目の要素も変更されました.なぜか考えてみましょう.わからなかったら下図在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?
ネストされた要素を正しくコピーする方法は「深いコピー」(deep copy)で、方法は
import copy



a = [0, [1, 2], 3]

b = copy.deepcopy(a)

a[0] = 8

a[1][1] = 9


在Python中,令values=[0,1,2];values[1]=values,为何结果是[0,[...],2]?