https://foramonth.tistory.com/20
1. Python - Call by reference
Python에서의 'Call by Object Reference'
파이썬의 변수에 대해 공부하다가 함수 인수 전달 방식인
- call by value
- call by reference
- call by object reference
에 대해 알게 되었다.
이들의 차이점에 대해 알아보자!
Call by Value
함수에 인수를 전달하는 방식이다.
변수의 값을 복사해 함수의 인자로 전달한다.
따라서, 함수 내에서 전달된 인자를 조작해도 함수 외부의 변수에는 영향을 미치지 않는다.
Call by Reference
함수에 인수를 전달하는 방식이다. Java 혹은 C언어의 포인터로 함수의 인자에 전달하는 방식이 이와 같은 방식이다.
변수가 가리키는 주소 값을 함수의 인자로 전달한다.
함수 내에서 전달된 인자를 조작하면, 함수 외부의 원본 변수의 주소값에 있는 값을 바꿔버린다. 따라서, 함수 내에서 변경된 사항이 함수 외부에도 영향을 미치게 된다.
call by value & reference
Call by Object Reference
Python에서 함수에 인수를 전달하는 방식이다.
call by reference vs call by object reference
Call by Object Refernce와 Call by Reference는 언뜻 보기에 비슷해 보인다. 하지만 위의 그림과 같은 차이가 분명히 존재한다. 두 방식이 어떻게 다른지 알아보자!
이 차이를 이해하기 위해서는 파이썬 객체의 mutable & immutable에 대해 이해해야 한다.
Python Glossary [docs.python.org/3/glossary.html]에는 아래와 같이 설명되어 있다.
object
- Any data with state and defined behavior. Also the ultimate base class of any new-style class.
mutable
- Mutable objects can change their value but keep their id().
imutable
- An object with a fixed value. Immutable objects include numbers, strings and tuples. Such an object cannot be altered. A new object has to be created if a different value has to be stored. They play an important role in places where a constant hash value is needed, for example as a key in a dictionary.
파이썬에서 모든 것은 객체이다.
값들은 변수 내에 저장되는 것이 아니라, 1, 2와 같은 객체가 생성되고 변수가 그 객체를 가리키도록 한다. 흔히 이름표라는 비유를 많이 사용한다. a = 1, c = 1이면, 1이라는 하나의 객체에 a와 c라는 이름표가 두개 붙어있는 것이다.
다음으로 mutable과 immutable에 대해 생각해보자.
mutable object는 자신의 id값은 일정하게 유지하지만, 객체의 값이 변할 수 있다. 하지만, immutable object는 객체의 값을 변경할 수 없다. 대표적으로 수, 문자열, 튜플과 같은 자료형이 있다.
Immutable Object
immutable object를 가리키는 변수의 값을 변경했을 때 어떤 일이 일어나는지 알아보자.
a = 1
a라는 변수에 1이 저장되어있는 것이 아니라, 1이라는 객체의 이름표가 a인 것이다.
def func(c):
c = 2
a = 1
func(a)
이렇게 함수에 a라는 변수를 전달하면, c라는 변수도 a가 가리키는 객체인 1을 가리키게 된다.
함수 내에서 c의 값을 2로 변경하게 되면, c라는 변수의 값이 1에서 2로 바뀌는 것이 아니라, 2라는 객체가 생성되고 1에 붙어있던 local variable 'c'가 2에 붙게 되는 것이다.
위와 같은 이유로 a = 1, b = 2인 상황에서 함수 내부의 c의 값을 1에서 2로 변경하면, c와 b의 id가 동일해진다. 2에 b(global)라는 이름표만 붙어있었는데, c라는 이름표(local)도 함께 붙게 되는 것이다.
실제로 위의 그림과 같은 일이 일어나는지 알아보자.
def func(c):
print('c before change : ',id(c))
c = 2
print('c after change : ',id(c))
a = 1
print('a before function: ',id(a))
b = 2
print('b before function: ',id(b))
func(a)
코드를 실행시킨 결과를 보면, a의 id와 c가 2로 바뀌기 전 id가 동일함을 확인할 수 있다.
또한, b의 id와 c가 2로 바뀐 후의 id도 동일함을 확인할 수 있다.
Mutable Object
리스트와 같은 mutable object에서 내부 값을 변경할 때, 어떤일이 일어나는지 알아보자.
리스트는 내부의 값을 변경할 수 있다.
따라서, 함수 내부에서 리스트의 끝에 5를 추가하면, 5가 추가된 리스트가 새로 생성되는 것이 아니라 동일한 id의 리스트에 5가 추가된다.
def func(arr):
arr.append(5)
a = [1,2,3,4]
func(a)
위의 코드를 살펴보자.
함수가 실행되면, arr라는 local variable도 a와 같은 객체([1,2,3,4])를 가리키게 된다.
여기서 arr.append(5)를 하게 되면, 리스트는 mutable하기 때문에 5가 추가된 새로운 객체가 생성되는 것이 아니라, 기존의 동일한 id를 가지는 리스트에 5가 추가된다.
따라서, 함수가 종료되고 local variable인 arr가 사라지고 난 후에도 a는 여전히 [1,2,3,4,5]를 가리키게 된다.
def func(arr):
arr = [5,6]
a = [1,2,3,4]
func(a)
이 코드에서는 어떤 일이 일어날까?
함수가 실행되면 arr도 a와 동일하게 [1,2,3,4]를 가리킨다.
arr = [5,6]이 실행되면, [5,6]이라는 새로운 리스트 객체가 생성되고 arr는 이를 가리키게 된다.
따라서, 함수가 종료된 이후에도 a는 여전히 [1,2,3,4]를 가리키고 있는 것이다.
2. 실습 Code - 오류 Check
결론: 각 iteration마다 w가 참조하는 값이 바뀌는데
해당 코드에서는 [ w , cost ]의 w가 모두 같은 주소값을 참조할 수 밖에 없기 때문에
w가 참조하는 값이 바뀔때마다 해당 값으로 모든 w 칼럼의 값이 바뀐다