明確な理由なしに使用されるPythonリストスライス構文
-
11-07-2019 - |
質問
時折、次のようなPythonコードで使用されるリストスライス構文が表示されます。
newList = oldList[:]
確かにこれは次と同じです:
newList = oldList
または何か不足していますか?
解決
NXCのように、Python変数名は実際にはメモリ内の特定の場所ではなく、オブジェクトを指します。
newList = oldList
は、同じオブジェクトを指す2つの異なる変数を作成するため、 oldList
を変更すると、 newList
も変更されます。
ただし、 newList = oldList [:]
を実行すると、" slices&quot ;;リストを作成し、新しいリストを作成します。 [:]
のデフォルト値は0およびリストの最後なので、すべてをコピーします。したがって、最初のリストに含まれるすべてのデータを含む新しいリストが作成されますが、もう一方を変更せずに両方を変更できます。
他のヒント
[:]
リストを浅く作成します元のリストメンバーへの参照を含むリスト構造のコピー。これは、コピーに対する操作が元の構造に影響しないことを意味します。ただし、リストメンバーに何かを行うと、両方のリストが引き続きそれらを参照するため、元のメンバーからメンバーにアクセスすると更新が表示されます。
ディープコピーは、すべてのリストメンバーのコピーも作成します。
以下のコードスニペットは、実行中の浅いコピーを示しています。
# ================================================================
# === ShallowCopy.py =============================================
# ================================================================
#
class Foo:
def __init__(self, data):
self._data = data
aa = Foo ('aaa')
bb = Foo ('bbb')
# The initial list has two elements containing 'aaa' and 'bbb'
OldList = [aa,bb]
print OldList[0]._data
# The shallow copy makes a new list pointing to the old elements
NewList = OldList[:]
print NewList[0]._data
# Updating one of the elements through the new list sees the
# change reflected when you access that element through the
# old list.
NewList[0]._data = 'xxx'
print OldList[0]._data
# Updating the new list to point to something new is not reflected
# in the old list.
NewList[0] = Foo ('ccc')
print NewList[0]._data
print OldList[0]._data
Pythonシェルで実行すると、次のトランスクリプトが生成されます。私たちは見ることができます 古いオブジェクトのコピーで作成されるリスト。オブジェクトのいずれかが持つことができます その状態は古いリストを参照して更新され、更新は オブジェクトが古いリストからアクセスされたときに表示されます。最後に、 新しいリストの参照は、古いリストに反映されていないことがわかります。 新しいリストは別のオブジェクトを参照しています。
>>> # ================================================================
... # === ShallowCopy.py =============================================
... # ================================================================
... #
... class Foo:
... def __init__(self, data):
... self._data = data
...
>>> aa = Foo ('aaa')
>>> bb = Foo ('bbb')
>>>
>>> # The initial list has two elements containing 'aaa' and 'bbb'
... OldList = [aa,bb]
>>> print OldList[0]._data
aaa
>>>
>>> # The shallow copy makes a new list pointing to the old elements
... NewList = OldList[:]
>>> print NewList[0]._data
aaa
>>>
>>> # Updating one of the elements through the new list sees the
... # change reflected when you access that element through the
... # old list.
... NewList[0]._data = 'xxx'
>>> print OldList[0]._data
xxx
>>>
>>> # Updating the new list to point to something new is not reflected
... # in the old list.
... NewList[0] = Foo ('ccc')
>>> print NewList[0]._data
ccc
>>> print OldList[0]._data
xxx
既に回答済みなので、簡単なデモを追加します。
>>> a = [1, 2, 3, 4]
>>> b = a
>>> c = a[:]
>>> b[2] = 10
>>> c[3] = 20
>>> a
[1, 2, 10, 4]
>>> b
[1, 2, 10, 4]
>>> c
[1, 2, 3, 20]
Pythonで「a = b」が「copy b to a」を意味するとは考えないでください。両側に変数がある場合、それを本当に知ることはできません。代わりに、「bに追加名aを与える」と考えてください。
bが不変オブジェクト(数値、タプル、文字列など)である場合、はい、コピーを取得します。しかし、それは不変( read only 、 unchangeable 、または WORM と呼ばれるべきだった)を扱うときは、常に 定義により、コピーを取得します。
bが可変である場合、真のコピーを確実に得るために常に何か特別なことを行う必要があります。 常に。リストでは、スライスと同じくらい簡単です:  a = b [:]。
可変性も、これが理由です:
def myfunction(mylist=[]):
pass
...は、あなたが思うように動作しません。
Cのバックグラウンドから来ている場合: '='の左側は常にポインターです。すべての変数は常にポインターです。変数をリストに入れた場合:  a = [b、c]、bが指す値へのポインターと、aが指すリストにcを入れました。その後、a [0] = dと設定すると、位置0のポインターは、dが指すものを指します。
copy-moduleも参照してください:  http://docs.python.org/ library / copy.html
浅いコピー:(メモリのチャンクをある場所から別の場所にコピーします)
a = ['one','two','three']
b = a[:]
b[1] = 2
print id(a), a #Output: 1077248300 ['one', 'two', 'three']
print id(b), b #Output: 1077248908 ['one', 2, 'three']
ディープコピー:(オブジェクト参照をコピー)
a = ['one','two','three']
b = a
b[1] = 2
print id(a), a #Output: 1077248300 ['one', 2, 'three']
print id(b), b #Output: 1077248300 ['one', 2, 'three']