web-dev-qa-db-ja.com

python参照ではなく値によるリスト

例を見てみましょう

a=['help', 'copyright', 'credits', 'license']
b=a
b.append('XYZ')
b
['help', 'copyright', 'credits', 'license', 'XYZ']
a
['help', 'copyright', 'credits', 'license', 'XYZ']

リスト「b」に値を追加したかったのですが、リスト「a」の値も変更されました。
[。
私の質問は、「 'b'を追加しても 'a'の値が変わらないように値で渡すにはどうすればよいですか?」です。

123
d.putto

公式Python FAQ で回答されています:

b = a[:]
172
phihag

リストをコピーするには、list(a)またはa[:]を使用できます。どちらの場合も、新しいオブジェクトが作成されます。
ただし、これらの2つのメソッドには、内部オブジェクトが参照をそのまま保持するため、可変オブジェクトのコレクションに制限があります。

>>> a = [[1,2],[3],[4]]

>>> b = a[:]
>>> c = list(a)

>>> c[0].append(9)

>>> a
[[1, 2, 9], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> b
[[1, 2, 9], [3], [4]]
>>> 

オブジェクトの完全なコピーが必要な場合は、 copy.deepcopy が必要です。

>>> from copy import deepcopy
>>> a = [[1,2],[3],[4]]

>>> b = a[:]
>>> c = deepcopy(a)

>>> c[0].append(9)

>>> a
[[1, 2], [3], [4]]
>>> b
[[1, 2], [3], [4]]
>>> c
[[1, 2, 9], [3], [4]]
>>> 
122
joaquin

パフォーマンスに関して、私のお気に入りの答えは次のとおりです。

b.extend(a)

パフォーマンスの観点から、関連する代替案が互いにどのように比較されるかを確認します。

In [1]: import timeit

In [2]: timeit.timeit('b.extend(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[2]: 9.623248100280762

In [3]: timeit.timeit('b = a[:]', setup='b=[];a=range(0,10)', number=100000000)
Out[3]: 10.84756088256836

In [4]: timeit.timeit('b = list(a)', setup='b=[];a=range(0,10)', number=100000000)
Out[4]: 21.46313500404358

In [5]: timeit.timeit('b = [elem for elem in a]', setup='b=[];a=range(0,10)', number=100000000)
Out[5]: 66.99795293807983

In [6]: timeit.timeit('for elem in a: b.append(elem)', setup='b=[];a=range(0,10)', number=100000000)
Out[6]: 67.9775960445404

In [7]: timeit.timeit('b = deepcopy(a)', setup='from copy import deepcopy; b=[];a=range(0,10)', number=100000000)
Out[7]: 1216.1108016967773
25
Kyr

また、次のことができます。

b = list(a)

これは、インデクサーとスライスをサポートしていないシーケンスでも動作します...

16
Daren Thomas

一次元のリストをコピーしたい場合は、

b = a[:]

ただし、aが2次元リストの場合、これは機能しません。つまり、aの変更は、bにも反映されます。その場合、使用

b = [[a[x][y] for y in range(len(a[0]))] for x in range(len(a))]
8
Rohan Saxena

Phihagの答えで述べたように、

b = a[:]

リストをスライスするとリストの新しいメモリIDが作成されるため、あなたのケースで機能します(つまり、メモリ内の同じオブジェクトを参照しなくなり、一方に加えた変更が他方に反映されないことを意味します)。

ただし、わずかな問題があります。リスト内のリストのようにリストが多次元の場合、単にスライスしてもこの問題は解決しません。高次元で行われた変更、つまり元のリスト内のリストは、2つの間で共有されます。

心配しないでください、解決策があります。モジュールコピーには、この問題を処理する巧妙なコピー手法があります。

from copy import deepcopy

b = deepcopy(a)

リストに含まれるリストのレベルに関係なく、新しいメモリIDでリストをコピーします!

6
Jordan Pagni

b = aを実行すると、単にaの同じメモリへの別のポインターを作成するため、bに追加するとaも変わります。

copy of aを作成する必要があり、これは次のように行われます。

b = a[:]
5
Gil.I

リストのコピーを作成するには、次を実行します。

b = a[:]
5
Rob Wouters

Extend()を使用してcopy()の機能を実装できることがわかりました

a=['help', 'copyright', 'credits', 'license']
b = []
b.extend(a)
b.append("XYZ") 
2
user3754245

次の解決策をお勧めします。

b = []
b[:] = a

これにより、すべての要素がaからbにコピーされます。コピーは参照コピーではなく、値のコピーになります。

2
VHS

b = list(a)

http://henry.precheur.org/python/copy_list を参照してください。

1
BenH