본문 바로가기
Computer Science/Python

[Python] list 복사 ([:], copy(), deepcopy())

by sohyunwriter 2021. 2. 11.

 

파이썬 ps를 하면서 많이 하기 쉬운 실수들에 대해 적는다.

 

다음 두 코드의 결과는 어떻게 될까?

하나는 맞고 하나는 이상한 결과를 배출한다.

 

1) 

class Solution(object):
    def subsets(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        results = []

        def dfs(nums, k, pos, subsets=[]):
            if k == 0:
                results.append(subsets)
                return

            for i in range(pos, len(nums)):
                subsets.append(nums[i])
                dfs(nums, k - 1, i + 1, subsets)
                subsets.pop()

        for i in range(len(nums) + 1):
            dfs(nums, i, 0, [])

        return results

sol = Solution()
print(sol.subsets(nums=[1, 2, 3]))

 

2) 

from typing import List

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        results = []

        def subset(pos, n, arr):
            if pos == n:
                return results.append(arr)

            subset(pos+1, n, arr + [nums[pos]])
            subset(pos+1, n, arr)

        subset(0, len(nums), arr=[])
        return results

sol = Solution()
print(sol.subsets(nums=[1, 2, 3]))

 

 

1) 코드의 결과

 

2) 코드의 결과

 

 

그 이유는 바로 append에 있다. 

1) 코드를 보면, dfs 함수에서 subsets의 주소값을 참조해서 results에 append했다.

하지만 subsets는 dfs 안에서 for문이 돌 때마다 계속 수시로 변화한다. 

그리고 맨 마지막에는 subsets는 []이 된다.

 

그렇기 때문에 최종적으로는 []이 출력되게 된다.

왜냐면 results에 append 된 값은 각각의 []의 주소값을 참조하도록 되어있기 때문이다.

그림으로 표현하면 다음과 같다.

 

첫 번째 if 통과 후 나온 어떤 list가 subsets를 참조하고, 

두 번째 if 통과 후 나온 어떤 list가 subsets를 참조하고...

이렇게 각 과정에서 같은 subsets를 가리키도록 저장된다.

 

 

하지만 우리가 원하는 결과는 아래와 같은 형태이다.

 

 

즉, 주소값이 아닌, 값을 복사하려면 

 

1) [:] 쓰기

results.append(subsets[:])

 

2) copy() 사용 (단, 2차원 이상의 list일 경우 deepcopy()를 써야 함)

results.append(subsets.copy())

 

그렇다면 2번째 코드는 왜 정상으로 작동할까?

그 이유는 subset 함수 내에 arr을 매번 호출했기 때문이다. 

따라서 각각의 함수에서는 서로 다른 arr이 전달됐을 것이고, 그 결과를 results에 저장해줬기 때문에 

우리가 원하는 대로 output이 나온다.