source

참조가 아닌 값별 파이썬 목록

manysource 2023. 5. 25. 22:10

참조가 아닌 값별 파이썬 목록

예를 들어 보겠습니다.

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[:]

하지만, 만약에a2차원 목록입니다. 당신에게 효과가 없을 것입니다.즉, 의 모든 변경 사항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