call by object reference

  • Call by assignment
  • 객체 참조에 의한 호출
  • stack frame 그림을 직접 그려보자.

    1. 변경할 수 없는 객체(immutable)의 경우
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      def change_value(num, new_num):
      num = new_num
      print('%d in change value' % num)


      # 파이썬에서 "="의 의미는 할당(assignment)
      # num은 new_num이 가리키는 값을 가리킨다.

      num = 10 # immutable(변경할 수 없는 객체)
      # num은 10을 가리킨다.
      # 10을 객체(object)라고 한다.

      change_value(num, 20)
      print(num)
      >> 20 in change value
      10
    • 두 결과값이 모두 num이 20이 나오지 않는다.
    • change_value 함수의 num은 글로벌 변수 num의 값을 복사한 것이 아니다.
    • change_value 함수의 num은 글로벌 변수 num의 값을 가리키는 것이다.
    • 따라서 call by value는 아니다.
    • num = new_num이 되면 num은 10을 가리키다가 20을 가리킨다.
    • change_value 함수가 종료되면 stack frame에서 사라진다.
    • 글로벌 변수 num에는 여전히 10이 남아있다.
    • 파이썬 함수 안에서는 call by reference처럼 해결할 수는 없다.
    • 하지만 다음처럼 해결할 수 있다.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # 반환값을 num으로 받음
      # num에 반환값을 할당해서 num이 20을 가리키도록 함
      def change_value(num, new_num):
      num = new_num
      print('%d in change value' % num)
      return num


      num = 10
      num = change_value(num, 20)
      print(num)
      >> 20 in change value
      20
    1. 변경할 수 있는 객체(mutable)의 경우
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # list는 변경할 수 있는 객체(mutable)
      li = [1, 2, 3]


      def change_elem(li, idx, new_num):
      li[idx] = new_num
      print(li)


      change_elem(li, 1, 100)
      print(li)
      >> [1, 100, 3]
      [1, 100, 3]
    • 이번에는 두 결과값이 다 같다.
    • li[idx]도 상수 객체이기 때문에 imutable이다.
    • 여기서 중요한 것은 li가 []의 object를 가리키는 것은 맞다.
    • 하지만 [] 내부 각 자리에서 또 1, 2, 3을 각각 가리킨다.
    • li[idx] = new_num이 실행되면, li[1] = 100이므로, li[1]이 2가 아닌 100을 가리키게 된다.
    • change_elem 함수가 종료되면, 함수는 사라진다.
    • 기존 li[1]도 100을 가리키고 있기 때문에 [1, 100, 3]이 된다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      li = [1, 2, 3]


      def change_elem(li, a, b, c):
      li = [a, b, c]
      print(li)


      change_elem(li, 1, 100, 3)
      print(li)
      >> [1, 100, 3]
      [1, 2, 3]
    • 위와 같은 경우는 바뀌지 않았다.

    • global 영역의 list li는 []을 가리키고 [] 안 각 자리는 1, 2, 3을 가리킨다.
    • change_elem 함수 내부에서도 object [ ]가 생성되게 된다.
    • global 영역의 1과 3 그리고 새로 지정한 100을 [] 안 각 자리가 가리키게 된다.
    • 파이썬에서는 자동적으로 같은 object를 가리키도록 해준다.
    • 그래서 change_elem 함수 내부 li는 내부에서 생성된 object []를 가리키게 된다.
    • 따라서 함수가 사라지면 기존 global li의 값은 변하지 않게 되는 것이다.

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      # tuple은 변경할 수 없는 객체(immutable)
      tu = (1, 2, 3)


      def change_elem(tu, a, b, c):
      tu = (a, b, c)
      print(tu)
      return tu


      tu = change_elem(tu, 1, 100, 2)
      print(tu)
      >> (1, 100, 2)
      (1, 100, 2)
    • tuple의 요소 값은 바꿀 수는 없다.

    • 그리고 또한 함수 내부에서도 바꾸는건 불가능하다.
    • 따라서 위처럼 tu를 반환시킨다.
    • return으로 받은 tu를 tu에다가 할당함으로 tu가 새로운 tu를 가리키도록 해준다.
Share