Programming/Python

[Python] Call by reference & Call by Value, 불변타입과 가변타입

빠른손 2022. 3. 26. 17:51
728x90

알고리즘 및 자료구조(연결리스트)를 공부하던 중 아래와 같은 의문이 들었습니다.

 

▶궁금했던 내용

아래 코드는 리트코드 21번 Merge Two Sorted Lists에 대한 풀이입니다.

https://leetcode.com/problems/merge-two-sorted-lists/

 

Merge Two Sorted Lists - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

# https://leetcode.com/problems/merge-two-sorted-lists/
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next


class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        result = ListNode()
        current = result

        while l1 and l2:
            if l1.val < l2.val:
                current.next = l1
                l1 = l1.next
            else:
                current.next = l2
                l2 = l2.next
            current = current.next

            if l1:
                current.next = l1
            else:
                current.next = l2

        return result.next


list1 = ListNode(1, ListNode(2, ListNode(4, None)))
list2 = ListNode(1, ListNode(3, ListNode(4, None)))

sol = Solution()
print(sol.mergeTwoLists(list1, list2))

위 코드 중 result = ListNode() 를 보면 result라는 변수를 선언하고 리스트노드 초기값으로 초기화를 했습니다.

바로 다음 행에서 current = result 를 보면 current라는 변수를 선언하고 result의 값(즉, 리스트노드 초기값)으로 초기화했습니다.

그 이후 return이 나오기 전까지 result는 전혀 건드린 적이 없고 current만 계속 값이 변화한 것을 알 수 있습니다.

또한, 리트코드 21번 문제에 대한 답은 result.next를 반환해야 정답이 되고 current.next는 오답입니다.

 

여기서 의문이 들었습니다. 아래 예를 들어보겠습니다.

test1 = "asdf"  # test1이 result의 역할
test2 = test1   # test2가 current의 역할

test2 = "oooo"  # test2, 즉 current의 값을 변경했습니다.
print(test1)
print(test2)

위 코드에서 test1은 result와 같고, test2는 current와 같다고 생각했습니다. 출력 값은 예상하시는대로

print(test1) ----> "asdf"

print(test2) ----> "oooo"

와 같이 test2의 값이 변경된다 해도 test1의 값은 처음에 test1의 값을 복사하여 가져오고 독립된 변수이기 때문에 변경될리가 없습니다.

 

위와 같은 원리라면 조금 전 위에서 설명한 result의 값도 current가 바뀐다고 한들 계속 ListNode()로만 존재해야 하는게 아닌가 하는 의문이 들었습니다.

 

지레짐작으로 값을 복사하는게 아니라 참조하는거 같은데 왜 test1, test2의 케이스에서는 복사를 하고 result, current 케이스에서는 참조를 하는걸까? 하는 의문이 들었지만 구글에 어떤 키워드로 검색해야할지도 몰랐습니다.

 

몇 시간 동안 고민하다 결국 Call by Reference와 Call by Value라는 키워드로 검색해보라는 조언을 얻었습니다.

 

▶불변 타입과 가변 타입?

구글링 한 결과, 파이썬에서는 초기화 시키는.. 또는 넘겨지는 객체의 종류에 따라서 값을 복사하느냐 참조하느냐가 결정된다는 것을 깨달았습니다.

 

불변 타입, Immutable object인 int, float, str, tuples 등 당일 값이거나 static속성인 값을 넘겨주면 call by value로 값이 복사되며 값을 받은 변수를 아무리 바꿔도 값을 넘겨준 기존의 변수에는 전혀 영향이 없어 안전하나는 장점이 있습니다.

 

하지만 가변 타입, Mutable object인 list, dict, set과 같은 객체를 넘기면 call by reference로 값이 참조가 됩니다.

 

▶결론

위 예시에서 test1, test2는 불변 타입을 넘겨주어 call by value가, result, current에서는 가변 타입을 넘겨주어 call by reference가 되었다는 결론을 지을 수 있었습니다.

728x90

'Programming > Python' 카테고리의 다른 글

[Python] f-string에 대해서  (0) 2022.02.20
[Python] 웹 크롤링(Web Crawling)  (0) 2022.01.26