10

私はUdacityを使用して作業しており、DaveEvansがリストプロパティに関する演習を紹介しました

list1 = [1,2,3,4]
list2 = [1,2,3,4]

list1=list1+[6]
print(list1)
list2.append(6)
print(list2)

list1 = [1,2,3,4]
list2 = [1,2,3,4]

def proc(mylist):
    mylist = mylist + [6]

def proc2(mylist):
    mylist.append(6)

# Can you explain the results given by the four print statements below? Remove
# the hashes # and run the code to check.

print (list1)
proc(list1)
print (list1)

print (list2)
proc2(list2)
print (list2)

出力は

[1, 2, 3, 4, 6]
[1, 2, 3, 4, 6]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4]
[1, 2, 3, 4, 6]

したがって、関数では、セットに6を追加しても表示されませんが、関数にない場合は表示されますか?

4

6 に答える 6

19

したがって、関数では、セットに6を追加しても表示されませんが、関数にない場合は表示されますか?

いいえ、それは起こりません。

何が起こるかというと、を実行するmylist = mylist + [6]と、まったく新しいリストが効果的に作成され、ローカルmylist変数に入れられます。このmylist変数は関数の実行後に消え、新しく作成されたリストも消えます。

OTOHを実行するmylist.append(6)と、新しいリストは作成されません。mylistすでに変数にリストを取得し、この同じリストに新しい要素を追加します。その結果、リスト(これもポイントされlist2ます)自体が変更されます。mylist変数は再び消えますが、この場合は元のリストを変更しました。

より視覚的な説明があなたを助けることができるかどうか見てみましょう:)

電話するとどうなりますかproc()

書くlist1 = [1, 2, 3, 4, 5]ときは、新しいリストオブジェクト(等号の右側)を作成し、list1このオブジェクトを指す新しい変数、を作成します。

新しいリストインスタンスとグローバル変数の作成

次に、を呼び出すときにproc()、別の新しい変数、を作成します。パラメータとしてmylist渡すため、同じオブジェクトを指します。list1mylist

メソッドを呼び出すとローカル変数が作成されます

ただし、この操作mylist + [6] により、まったく新しいリストオブジェクトが作成されます。このオブジェクトの内容は、が指すオブジェクトの内容にmylist加えて、次のリストオブジェクトの内容です。つまり、[6]。この新しいオブジェクトをに帰するのでmylist、シナリオは少し変わり、もうmylist指している同じオブジェクトを指していlist1ません。

mylistは新しいリストオブジェクトを指します

私が言っていないのは、それmylistローカル変数であるということです。関数の終了後に消えproc()ます。したがって、proc()実行が終了すると、次のようmylistになります。

mylistはなくなりました

によって生成されたオブジェクトを指す変数は他にないためmylist + [6]、それも消えます(ガベージコレクター*がオブジェクトを収集するため)。

GCはリストを収集します

結局、が指すオブジェクトlist1は変更されないことに注意してください。

電話するとどうなりますかproc2()

を呼び出すと、すべてが変わりますproc2()。最初は同じです:リストを作成します...

新しいリストインスタンスとグローバル変数の作成

...そしてそれをパラメータとして関数に渡します。関数はローカル変数を生成します:

メソッドを呼び出すとローカル変数が作成されます

+ただし、新しいリストを生成する連結演算子を使用する代わりにappend()、既存のリストにメソッドを適用します。このappend()メソッドは新しいオブジェクトを作成しません; 代わりに、既存のものを_変更します。

リストに値を追加する

関数の終了後、ローカル変数は消えますが、それとによって示される元のオブジェクトはlist1すでに変更されています。

それはまだ変更されています

がまだポイントしているのでlist1、元のリストは破棄されません。

編集:目の前で起こっているこれらすべてのことを確認したい場合は、この根本的に素晴らしいシミュレーターにアクセスしてください:

ここに画像の説明を入力してください

*ガベージコレクターとは何かわからない場合は...まあ、あなたはあなた自身の質問を理解した後すぐに発見するでしょう。

于 2012-05-25T03:40:29.383 に答える
3

Pythonの変数は、常に参照と考えることができます。引数を指定して関数を呼び出すと、実際のデータへの参照が渡されます。

代入演算子(=)を使用すると、まったく新しいオブジェクトを参照するためにその名前が割り当てられます。したがって、mylist = mylist + [6]mylistの古い内容と6を含む新しいリストを作成し、新しいリストを参照するように変数mylistを割り当てます。list1はまだ古いリストを指しているため、何も変更されません。

一方、.appendを使用すると、変数が参照するリストに要素が実際に追加されます。つまり、変数に新しいものは何も割り当てられません。したがって、2番目の関数は、list2が参照するリストを変更します。

于 2012-05-25T03:41:03.000 に答える
2

通常、機能の最初のケースでは、proc宣言した場合にのみ、割り当てによってグローバルリストを変更できます。

global mylist

mylist最初に、パラメータとして渡されませんでした。ただし、この場合、mylistグローバルおよびローカル のエラーメッセージが表示されますname 'mylist' is local and global。で何が起こるかとprocいうと、割り当てが行われるときにローカルリストが作成されます。関数が終了するとローカル変数がなくなるため、ローカルリストへの変更の影響は、後で印刷されるときにプログラムの残りの部分に伝播されません。

ただし、2番目の関数proc2では、リストに割り当てるのではなく追加してリストを変更globalしているため、キーワードは不要であり、リストへの変更は他の場所に表示されます。

于 2012-05-25T03:37:23.017 に答える
2

すでに示した包括的な回答だけでなく、次と同じ外観の構文が必要な場合は、注意する価値があります。

mylist = mylist + [6]

...それでもリストを「インプレース」で更新したい場合は、次のことができます。

mylist += [6]

これは、最初のバージョンと同じことをするように見えますが、実際には次と同じです。

mylist.extend([6])

(これextendは、反復可能オブジェクトの内容を1つずつ追加しますが、append指定されたものはすべて取得し、それを1つの項目として追加することに注意してください。完全な説明については、追加と拡張を参照してください。)

于 2012-06-07T11:35:13.930 に答える
0

これは、何らかの形で、非常に一般的な質問です。私は数日前に自分自身を渡すPythonパラメータを説明するのに苦労しました。基本的に、これらの1つは新しいリストを作成し、もう1つは既存のリストを変更します。後者の場合、リストを参照するすべての変数は、同じオブジェクトであるため、変更を「認識」します。

于 2012-05-25T04:23:26.630 に答える
0

3行目では、これを行いました

list1=list1+[6]

したがって、上記の行の後に以下を実行すると、

print (list1)

これは、startおよびprocプロシージャで作成したlist1を出力し、関数proc内に新しいリストを作成するlist1+[6]を追加します。[6]を追加する場合と同様に、新しいリストを作成するのではなく、既存のリストにリストアイテムを追加します。

ただし、覚えておいてください。7行目で、リストを再度作成しました

list1 = [1,2,3,4]

ここで、list1を明示的に呼び出して印刷する必要があります。これにより、再初期化したlist1は出力されますが、前のlist1は出力されません。

于 2012-05-25T08:00:53.470 に答える