참조가 아닌 값별 파이썬 목록
예를 들어 보겠습니다.
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의 값이 바뀌지 않도록 어떻게 값으로 전달할 수 있을까요?"입니다.
Python에서는 값으로 어떤 것도 전달할 수 없습니다.의 복사본을 만들고 싶은 경우:a
공식 Python FAQ에 설명된 대로 명시적으로 이를 수행할 수 있습니다.
b = a[:]
사용할 수 있는 목록을 복사하려면list(a)
또는a[:]
두 경우 모두 새 개체가 생성됩니다.
그러나 이 두 가지 방법은 내부 객체가 참조를 그대로 유지하기 때문에 변경 가능한 객체의 컬렉션에 제한이 있습니다.
>>> 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]]
>>>
성능 면에서 제가 가장 좋아하는 답변은 다음과 같습니다.
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
또한 다음을 수행할 수 있습니다.
b = list(a)
인덱서와 슬라이스를 지원하지 않는 시퀀스에서도 작동합니다.
1차원 목록을 복사하려면 다음을 사용합니다.
b = a[:]
하지만, 만약에a
2차원 목록입니다. 당신에게 효과가 없을 것입니다.즉, 의 모든 변경 사항a
에도 반영됩니다.b
이 경우, 사용
b = [[a[x][y] for y in range(len(a[0]))] for x in range(len(a))]
그의 대답에서 피하그가 언급했듯이,
b = a[:]
목록을 슬라이싱하면 목록의 새 메모리 ID가 생성되므로 사용자의 경우에 적합합니다(즉, 메모리에서 동일한 개체를 더 이상 참조하지 않으며 한 개체에 대한 변경 내용은 다른 개체에 반영되지 않습니다).
하지만, 약간의 문제가 있습니다.목록 내의 목록과 같이 목록이 다차원인 경우에는 단순히 슬라이스만 해도 이 문제가 해결되지 않습니다.더 높은 차원, 즉 원래 목록 내의 목록에서 변경한 내용은 두 가지 사이에서 공유됩니다.
초조해 하지 마세요, 해결책이 있습니다.모듈 복사에는 이 문제를 해결하는 훌륭한 복사 기술이 있습니다.
from copy import deepcopy
b = deepcopy(a)
목록에 포함된 수준 수에 상관없이 새 메모리 ID를 가진 목록을 복사합니다!
을 할 때는.b = a
당신은 단순히 a의 동일한 메모리에 다른 포인터를 만들기 때문에 b에 추가하면 a도 변경됩니다.
의 복사본을 만들어야 합니다. 이 작업은 다음과 같이 수행됩니다.
b = a[:]
목록의 복사본을 만들려면 다음을 수행합니다.
b = a[:]
extend()를 사용하여 copy()의 기능을 구현할 수 있다는 것을 알게 되었습니다.
a=['help', 'copyright', 'credits', 'license']
b = []
b.extend(a)
b.append("XYZ")
다음 솔루션을 권장합니다.
b = []
b[:] = a
이렇게 하면 모든 요소가 a에서 b로 복사됩니다.복사본은 참조 복사본이 아니라 값 복사본입니다.
b = list(a)
http://henry.precheur.org/python/copy_list 을 참조하십시오.
언급URL : https://stackoverflow.com/questions/8744113/python-list-by-value-not-by-reference
'source' 카테고리의 다른 글
경고(예산), 초기에 대한 최대값 초과 (0) | 2023.05.25 |
---|---|
WPF 및 Winforms의 UI 스레드에 있는지 여부를 감지하는 중 (0) | 2023.05.25 |
ADT 22로 업그레이드한 후 라이브러리가 APK에 더 이상 추가되지 않음 (0) | 2023.05.25 |
파이썬에서 "."와 "+=[]"의 차이점은 무엇입니까? (0) | 2023.05.25 |
스크립트에서 stderr과 stdout을 동일한 줄에 있는 다른 파일로 리디렉션하는 방법은 무엇입니까? (0) | 2023.05.25 |