2

したがって、次のようにネストした 4 x 3 のネストされたリスト (4 行、3 列) があります。

>>> c= [x[:] for x in [[None]*3]*4]
>>> print c
[[None, None, None], 
 [None, None, None], 
 [None, None, None], 
 [None, None, None]]

この他のSOの質問は、他の方法が機能しない理由をうまく説明しているため、この方法でネストされたリストを初期化しました。(c = [[なし]*3]*4 のように)

今、最初の行のすべての要素を 0 に更新したい。つまり、すべての要素を設定したい

c[0] to 0. So I tried the following:
>>> for x in c[0]: x = 0
...
>>> c
[[None, None, None], [None, None, None], [None, None, None], [None, None, None]]
>>>

ご覧のとおり、要素は更新されていません。ただし、以下は機能しました。

>>> c[0] = [0 for x in c[0]]
>>>
>>> c
[[0, 0, 0], [None, None, None], [None, None, None], [None, None, None]]

0 の新しいリストを作成し、それを c[0] に割り当てているので、そうなることはほぼ確実でした。

とにかく、次に for ループを使用し、最初の列 (つまり、すべての行の最初の要素) を 0 に更新しようとしたところ、うまくいきました。

>>> for x in c: x[0] = 0
...
>>> c
[[0, None, None], [0, None, None], [0, None, None], [0, None, None]]

この for ループの更新は、前の for ループの更新とは異なることを理解しています。最初の更新は単一の要素をループしようとしたのに対し、これはリストをループし、各リストの最初の要素にアクセスするだけだからです。

他の名前を指している名前について何かが欠けていると確信していますが、ここで正確な問題が何であるかを特定することはできません。誰か助けてくれませんか?

4

3 に答える 3

3
for x in c[0]: x = 0

このループでは、実際にはそのリストに存在する整数への新しい参照を作成し、それらの新しい参照を変更しています。

整数は不変であるため、元の参照は影響を受けません。さらに、割り当てはインプレース操作ではないため、可変オブジェクトにも影響しません。

>>> a = b = 1
>>> b += 1     # in-place operation, this will work differently for mutable objects
>>> a, b       # a is still unchanged
(1, 2)

割り当て操作は可変オブジェクトにも影響しません。

>>> x = y = [1, 1]
>>> x = 2 # `x` now points to a new object, number of references to [1, 1] decreased by 1
>>> x, y
(2, [1, 1])

ただし、インプレース操作は次のようになります。

>>> x = y = [1, 1]
>>> x.append(2)
>>> x, y
([1, 1, 2], [1, 1, 2])

したがって、上記のループは実際には次と同等です。

x = c[0]
x = 0    #this won't affect `c[0]`
x = c[1]
x = 0
...

このループでは、実際に c[0] を新しいリスト オブジェクトを指すように変更しました。

>>> c= [x[:] for x in [[None]*3]*4]
>>> c= [x[:] for x in [[None]*3]*4]
>>> print id(c[0])
45488072
>>> c[0] = [0 for x in c[0]]
>>> print id(c[0])              #c[0] is a new list object
45495944
于 2013-10-29T06:23:20.233 に答える
1

今、最初の行のすべての要素を 0 に更新したい。つまり、すべての要素をc[0]0 に設定したい。だから私は次のことを試した:

>>> for x in c[0]: x = 0

>>> c
[[None, None, None], [None, None, None], [None, None, None], [None, None, None]]
>>>

ご覧のとおり、要素は更新されていません。

これは、 c[0]xの各値が順番に与えられたためNoneです。つまり、効果的に次のように言っています。

x = None
x = 0
x = None
x = 0
x = None
x = 0

これは何の役にも立ちません。

ただし、以下は機能しました。

>>> c[0] = [0 for x in c[0]]
>>>
>>> c
[[0, 0, 0], [None, None, None], [None, None, None], [None, None, None]]

0 の新しいリストを作成し、それを c[0] に割り当てているので、そうなることはほぼ確実でした。

これc[0]は、の最初の要素 (リスト) への参照またはエイリアスであるため機能しcます。新しい値を割り当てることができ、元のcコンテナーに影響を与えます。ここで重要なのは、ライトスルー参照/エイリアスのアイデアです。Pythonコミュニティがこれを何と呼ぶ傾向があるかはわかりませんが(私は主にC ++プログラマーです)、機能的にc[0]はその要素を参照し、c上書きできます。 要素値 ( ) の不変コピーを効果的に見たc[0]ようxに、上記とは異なりますが、その値はコンテナーへの接続または書き込み機能を維持しませんでした。これは、単純な「スカラー」値だったためです。xNonecNone

変数は、割り当てられた値の不変のコピーを効果的に参照し、それ以上の割り当てがそれらの関連付けを解除する場合もあれば、割り当てられた値自体を実際に参照し続けて、追加の書き込みで変更できるようにするという考えは、実際には一般的です。いくつかのインタープリター言語に対応しています (たとえば、Ruby も同様です)。最初は戸惑う!これらの言語は、これらの「参照」が明示的で独自の構文/表記法を持つ C++ と言うよりも使いやすいと思わせたいと思っていますが、実際にはすぐに噛まれて、とにかく違いを理解することを学ばなければなりません。copy.deepcopyデータの真の独立したコピーが必要な場合。彼らは直観的であるように見えたいと思っていますが、直観的なこと (値のディープ コピー) は、大きなコンテナーやオブジェクトに対して実行するにはコストがかかりすぎます。そのため、最近のスクリプト言語は、データを安全にコピーしたと思われるものに書き込みを許可するという危険な動作を代わりに採用する傾向があります。言語を数週間使用した後、おそらくすべてクリックします....最初は混乱しますが、実際にも便利です-元の変数名、すべてのキーとインデックスを使用してデータを参照し、特定のものに絞り込む必要がありますスカラー値は非常に冗長になる可能性があり、もちろんこれは、関数がパーツを操作できるようにするために必要な抽象化です。複雑なオブジェクト/コンテナの残りのオブジェクトについて知る必要なく渡されます....

とにかく、for ループを使用して、最初の列 (つまり、すべての行の最初の要素) を 0 に更新しようとしたところ、うまくいきました。

>>> for x in c: x[0] = 0
...
>>> c
[[0, None, None], [0, None, None], [0, None, None], [0, None, None]]

これが機能するxのは、 が参照/エイリアスとして各リストに順番にバインドされているためです。また、リストは「複雑な」オブジェクトであるため、参照/エイリアスによって、上記で説明したライトスルー機能が可能になります。

この for ループの更新は、前の for ループの更新とは異なることを理解しています。最初の更新は単一の要素をループしようとしたのに対し、これはリストをループし、各リストの最初の要素にアクセスするだけだからです。

于 2013-10-29T06:32:45.390 に答える
1

いずれの場合も、何かへx参照です。

への参照の場合Noneは、 のインスタンスを作成し、それを参照するようint(0)に切り替えxます。というわけで、ここcは一切関与しません。

それ以外の場合xは のコンポーネントへの参照であるcため、そのコンポーネントを変更すると、変更が に反映されます。c

于 2013-10-29T06:24:28.007 に答える