>  기사  >  백엔드 개발  >  Python의 얕은 복사, 깊은 복사 및 참조 메커니즘에 대한 자세한 설명

Python의 얕은 복사, 깊은 복사 및 참조 메커니즘에 대한 자세한 설명

高洛峰
高洛峰원래의
2017-03-23 17:43:071439검색

이번 주에 몇 가지 문제가 발생했는데, 한동안 기초 지식이 정리되지 않았다면 아직 복습해야 할 잊어버린 부분이 있다는 것을 깨달았습니다. 여기에 기록해 두겠습니다.

이전

먼저 발생한 문제를 간략하게 설명하세요. 요구 사항은 2장의 인쇄 결과를

详解Python浅拷贝、深拷贝及引用机制

다음과 같이 작성하는 것입니다. 보시다시피, a는 목록 목록 객체를 가리킵니다. Python에서 이러한 할당 문은 실제로 a가 목록의 메모리 주소를 가리킨다는 것을 의미하며, 이는 포인터와 유사한 개념으로 간주될 수 있습니다.

그리고 b는 a 객체를 목록으로 감싸고 5를 곱하므로 b는 모든 요소 a

를 포함하는 큰 목록처럼 보일 것입니다. 가 추가되면 암묵적인 의미는 메모리의 목록이 수정되었으며 이 객체를 참조하는 모든 객체가 변경된다는 것입니다.

a의 id를 출력하고, 동시에 id를 출력합니다. 객체 b에 포함된 요소 a의 목록 b에서 각 요소의 ID가

详解Python浅拷贝、深拷贝及引用机制

과 동일하다는 것을 알 수 있습니다. 객체 a의 id(메모리 주소)는 10892296입니다. b가 a를 새 목록으로 래핑하더라도 이 요소는 여전히 동일한 주소를 가진 객체를 참조합니다.

详解Python浅拷贝、深拷贝及引用机制

이후 a에 추가 작업을 수행했습니다. 목록은 변수 개체이므로 메모리 주소는 변경되지 않았습니다. 그러나 메모리에서 이 주소에 대해 참조되는 모든 개체가 함께 변경되는 것을 볼 수 있습니다. 위 테스트 차트의 구분선 아래쪽에서 시작합니다.

이것은 Python 참조 메커니즘과 얕은 복사 및 깊은 복사에 대한 검토로 이어집니다

Python의 참조 메커니즘



참조 메커니즘 사례 1

위의 예에서 Python을 볼 수 있습니다. 최종 결과는 두 개체가 모두 콘텐츠를 참조한다는 것입니다.

그러면 다음 예를 살펴보자

B는 A를 전달하고 또한 id 17446024를 참조합니다. 주소의 내용과 id(메모리 주소) 둘은 완전히 동일합니다

따라서 A A[0]=3 또는 A[3].append(6) 연산을 통해 이 메모리의 내용을 수정합니다(목록은 변수이기 때문입니다) 객체, 메모리 주소는 변경되지 않습니다. 이에 대해서는 나중에 이야기하겠습니다)

이것은 가장 기본적인 참조 사례입니다(또한 A와 B가 모두 동일한 메모리 주소를 가리키므로 내용은 다음에서 수정됩니다). B는 A에도 반영될 수 있다)

详解Python浅拷贝、深拷贝及引用机制

참조 메커니즘 사례 2

다른 사례를 살펴보자

질문을 보면 요소 2가 목록 자체로 대체될 것으로 보입니다. 결과는 A=[1,[1,2,3],3]

그러나 그렇지 않습니다. ! 빨간 박스 안에는

이 무한히 많이 중첩되어 있는 것을 볼 수 있습니다. 왜 그럴까요?

사실 A가 목록 [1,2,3]을 가리키기 때문입니다. 이 예에서는 A의 두 번째 요소만 A 개체 자체를 가리키므로 의 두 번째 요소일 뿐입니다. A. 구조가 바뀌었어요! 그러나 A는 여전히 해당 객체를 가리킵니다

A의 ID를 인쇄하면 가리키는 내용이 변경되지 않았음을 알 수 있습니다! !

详解Python浅拷贝、深拷贝及引用机制

보세요, A의 방향은 변하지 않았습니다

详解Python浅拷贝、深拷贝及引用机制

그럼 최종 출력 효과를 얻으려면 [ 1, [1,2,3],3], 어떻게 운영해야 할까요?

여기서는 얕은 복사를 사용하겠습니다.


详解Python浅拷贝、深拷贝及引用机制

얕은 복사와 깊은 복사

얕은 카피

이제 얕은 복사와 깊은 복사에 대해 이야기해 보겠습니다. 위 방법은 실제로 얕은 복사, 얕은 복사만 수행합니다. 즉, 원본 참조 개체를 복사하지만 더 이상 동일한 개체 주소를 참조하지 않습니다.

아래 예를 보면 B = A[:] 연산을 통해 얕은 복사를 수행한 후 A와 B가 참조하는 메모리 주소가 이미 다른 것을 알 수 있습니다

A와 B 내부 요소의 참조 주소는 여전히 동일하므로 이에 대해 매우 주의하세요! 차이가 있습니다! ! !

A와 B의 참조 메모리 주소의 차이는 B에서 수행하는 작업이 A에 영향을 미치지 않는다는 것을 의미합니다.

详解Python浅拷贝、深拷贝及引用机制

얕은 복사본 요약:

그래서 얕은 복사본은 참조, 새 개체 및 원본을 복사하는 것으로 요약할 수 있습니다. 개체는 구별되지만 내부 요소의 주소 참조는 여전히 동일합니다

그런데 얕은 복사도 문제가 발생합니다. 예를 들어 다음 상황에서 볼 수 있듯이 A와 B의 ID(메모리 주소)가 다르도록 A의 얕은 복사본을 할당했습니다.

따라서 A[0]=8을 수정하면 A와 B는 독립적인 참조이지만 중간 [4 ,5,6]에 중첩 목록이 있기 때문에 B는 영향을 받지 않습니다.

우리는 이 [4,5,6]을 다음과 같이 이해할 수 있습니다. A와 B는 여전히 함께 참조합니다. 즉, A와 B의 두 번째 요소에 대해 그들은 여전히 ​​동일한 A 메모리 주소를 가리킵니다.

게다가 int는 불변형이므로 A[0]을 8로 변경하면 참조 주소도 변경됩니다! 이는 B[0] 요소의 참조와 구별된다.

详解Python浅拷贝、深拷贝及引用机制

딥 카피

그러면 이런 상황에 어떻게 대처해야 할까요? Python 모듈에 있는 복사 모듈을 사용해야 합니다.

복사 모듈에는 2가지 기능이 있습니다

1: copy.copy(복사하려는 객체): 이것은 얕은 복사본이며, 이전 목록의 [:] 작업의 성격은 동일합니다.

2: copy.deepcopy(복사하려는 개체): 이는 전체 복사와 마찬가지로 새 개체를 생성합니다.

아래 예를 보면 A를 B에 할당하면 이렇게 됩니다. 완전히 독립적입니다. A의 불변 요소를 수정하든 A의 중첩된 가변 요소를 수정하든 결과는 B에 영향을 미치지 않습니다.

내 이해는: 깊은 복사는 재귀 복사라고 할 수 있으며 중첩된 모든 요소를 ​​복사합니다.

详解Python浅拷贝、深拷贝及引用机制

딥 카피 요약:

딥 카피의 효과는 동일합니다. 얕은 복사. 객체의 참조에서 새 참조를 생성하는 것 외에도 모든 중첩된 요소를 하나씩 분리하는 데 도움이 됩니다.

얕은 복사와 깊은 복사의 차이점을 보여주기 위해 직접 그림 2개를 그렸습니다. 🎜>
얕은 복사 후에도 목록에 있는 불변 요소의 참조 주소는 여전히 동일하지만 불변 요소이기 때문에 불변 요소가 변경된 후에 참조 주소는 다음과 같습니다. 원래 참조 주소에 영향을 주지 않고 새 주소입니다.




详解Python浅拷贝、深拷贝及引用机制

详解Python浅拷贝、深拷贝及引用机制

요약
자, 얕게 갑니다. copy 그리고 deep copy의 메커니즘은 기본적으로 이해됩니다.

설명해야 할 특별한 상황도 있습니다

불변 유형의 경우: int, str, tuple, float 및 기타 요소가 수정된 후에는 참조 주소가 없습니다. 아래와 같이 직접 변경됩니다.


详解Python浅拷贝、深拷贝及引用机制
단, 불변 유형 내부에 중첩된 변수 유형이 있는 경우에도 딥 카피를 사용할 수 있습니다

详解Python浅拷贝、深拷贝及引用机制

또한 가장 일반적으로 사용되는 방법은 다음 예와 같이 직접 할당(또는 참조의 직접 전달)입니다.

그는 a와 b를 결합합니다. 두 개의 변수 요소가 다음을 가리킵니다. 동시에 메모리 주소를 지정하므로 모든 변경 사항은 a와 b에 영향을 미칩니다

详解Python浅拷贝、深拷贝及引用机制

마지막으로

변수 유형: list , set , dict

불변 유형: int, str , float , tuple

얕은 복사 방법: [:] , copy.copy() , 팩토리 함수 사용(list/dir/set )

깊은 복사 메소드: copy.deepcopy()


위 내용은 Python의 얕은 복사, 깊은 복사 및 참조 메커니즘에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.