[Python] Call by Reference / Call by Value | 파이썬에선 뭘 쓸까? | Mutable & Immutable

2022. 7. 16. 15:27개발공부 기강잡자/Python

Call by Value와 Call by Reference의 차이

1. Call by Value란? (값에 의한 호출) 

: 함수가 인자로 받은 값을 복사하여 처리한다!

인수와 매개변수가 다른 메모리 공간을 사용한다. 인수의 값만 전달하여 매개변수의 주소에 값을 복사하여 사용하기 때문에 인수와 매개변수의 메모리 주소는 다르다! 

값 자체를 넘겨주는 것이기 때문에 함수 내에서 매개변수로 이런저런 작업을 하더라도 값을 넘겨준 변수의 값에는 변화가 없다!

 

2. Call by Reference란? (참조에 의한 호출) 

: 인수의 주소 값을 함수에 전달한다. 주소를 참조하여 사용하기 때문에 함수에 전달한 인자에 바로 값을 처리하게 된다. 

보통 함수를 정의할 때 매개변수 앞에 & 혹은 *을 붙여 선언하면, 그 함수는 매개변수로 받은 변수의 값이 아닌 주소를 참조하게 된다.

따라서, 함수 내에서 해당 매개변수의 값을 변경하면, 매개변수의 주소값에 있는 값을 변경하기 때문에 원본 변수의 값을 변경하게 된다.

 

3. 차이

: Call by Value를 하면 값을 복사하여 새로운 메모리에 할당하기 때문에 사용하는 메모리가 늘어나게 된다. 하지만 원래의 값에 영향을 주지 않기 때문에 안전하다!

Call by Reference는 추가적인 메모리를 사용하지 않고 값을 처리할 수 있다! 하지만 변수의 주소를 참조하기 때문에 실행에 영향을 줄 수도 있으니 주의해야한다.


그래서, Python 에서는 ?!

Call by Assignment 방식을 따른다. Call by assignment 란 Parameter로 전달되는 객체의 형식에 따라 객체 참조 방식이 달라지는 방식이다.

→ 넘겨지는 객체의 종류에 따라서 결정된다!

 

그렇다면, 객체의 종류라는게 뭘까? 파이썬에서는 Mutable 객체와 Immutable 객체로 분류한다.

 

Mutable 객체

: 변하기 쉬운 객체 라는 뜻으로, 여기에 속하는 객체는 list, dict, set 등이다.

Immutable 객체

: 변하지 않는 객체라는 뜻으로, int, float, str, tuple 등이 속한다.

a = "hi"
a = "hello"

실제로 이 코드를 실행할 때, a라는 변수의 주소에 들어있는 값이 바뀌는게 아니라, 값이 새롭게 메모리에 바인딩되고 해당 객체를 a라는 변수가 바인딩한다. (id(a) 명령어를 실행하여 확인해보자)

반면에, 리스트와 같은 mutable 객체는 원소의 값을 바꿔도 주소는 바뀌지 않고 값만 변경된다.

 

아무튼, ★★★★중요 표시 백만개★★★★

Mutable 객체는 call by reference 방식으로, immutable 객체는 call by value 방식으로 호출된다.

 따라서 mutable 객체인 list를 매개변수로 받는 경우에는 매개변수의 주소를 전달한다.

def change0(arr):		# 리스트 원소를 모두 0으로 바꾸는 함수
    for i in range(len(arr)):
        arr[i] = 0
	
one_arr = [1] * 10
# 호출 전
print(one_arr)

change0(one_arr)

# 호출 후
print(one_arr)

위의 코드는 데이터가 1 인 10개의 원소로 구성된 list를 change0 이라는 함수에 전달하는 소스이다.

수행결과

이 코드를 실행하면 함수에서 리턴값을 받아 값을 변수에 바인딩하는 작업 필요없이, 함수 호출 후에 매개변수로 전달한 one_arr의 값이 변경되어 있는 것을 확인할 수 있다.

 

✔ 반면에 immutable 객체인 str을 매개변수로 받는 경우에는

def hello(str):
	str = "hello"
	return str
    
s = "hi"
hello(s)

print(s)

라는 코드를 실행하면, s의 값은 그대로 "hi"이다.

수행결과

 hello 함수를 통해 s 의 값을 "hello"라는 값으로 변경하고 싶다면

def hello(str):
	str = "hello"
	return str
    
s = "hi"
print("함수 호출 전 :", s)

s = hello(s)

print("함수 호출 후 :", s)

수행결과

이렇게 hello 함수의 리턴값을 받아 s 변수에 바인딩 해야 s의 값이 "hello"로 변경된 것을 확인할 수 있다.

 

이런 특성을 잊지않고 코딩하면 좀더 원할한 코딩이 가능할 것 같다. (❁´◡`❁)