-
[Python] Call by assignmentProgramming Language/Python 2021. 4. 16. 17:15
파이썬과 다른 언어의 차이점은 함수 인자 전달 방식에서도 나타납니다. 파이썬의 인자 전달 방식은 Call by assignment라고 하는데, 먼저 기존의 Call by value와 Call by reference를 간단히 짚고 Call by assignment를 살펴보겠습니다.
Call by value VS Call by reference
1. Call by value
함수 호출 시 전달되는 인자의 값을 복사해서 함수의 매개변수에 담아 함수 내부에서 사용하는 방식을 말합니다. 따라서, 함수 내부에서 인자로 들어온 값을 변경해도 값을 전달한 외부 변수의 값은 변경되지 않습니다.
2. Call by reference
함수 호출 시 전달되는 인자의 레퍼런스(=메모리 주소)를 매개변수에 담아 함수 내부에서 사용하는 방식입니다. C 언어에서 포인터를 사용해 변수의 메모리 주소를 담아 값을 변경하는 것이 대표적인 예시에요. 따라서, 함수 내부에서 매개변수를 이용해 레퍼런스가 가리키는 값을 변경하면, 레퍼런스를 전달한 외부 변수의 값도 변경됩니다.
Call by assignment
파이썬은 모든 것이 객체이기 때문에, C언어나 JAVA와 달리 어떤 종류의 객체가 인자로 전달되는냐에 따라 결과가 달라지는 Call by assignment 방식을 취합니다. 사실, 기본적으로 파이썬의 변수는 항상 객체의 레퍼런스를 담기 때문에, 함수를 호출해서 객체를 인자로 전달하면 매개변수에는 인자에 담긴 객체의 레퍼런스가 그대로 전달됩니다. 즉, 함수 호출시에는 항상 Call by reference로 동작합니다. 다만, 함수 내부에서 객체의 레퍼런스가 담겨 있는 매개변수를 조작할 때, 해당 객체의 종류에 따라 동작 방식이 달라집니다. 여기서 분기 기준이 되는 파이썬의 객체 종류는 변경가능한 객체(Mutable object)와 변경불가능한 객체(Immutable object), 두 가지로 나뉠 수 있습니다.
1. 변경불가능한 객체(Immutable object)
def immutable_call(x): x += 5 print('local:', x) a = 10 immutable_call(a) # local: 15 print(a) # 10
int, float, str, bool, tuple, frozenset 등이 여기에 속합니다. Immutable한 객체가 함수 인자로 전달될 때는 함수 내부에서 매개변수의 내용을 변경해도 함수 바깥에서 인자로 전달한 변수의 객체는 변경되지 않습니다. 즉, 마치 Call by value처럼 동작합니다. (엄밀히 말하면, 'Immutable한 객체 10에 5를 더해서 15로 변경한다는 것'은 10이 변경이 불가능하기 때문에 기존 객체 10을 가리키는 것을 그만두고, 새로운 객체 15를 만들어 가리킨다는 의미입니다.)
'마치 Call by value처럼 동작한다'라고 말한 이유를 또 다른 Immutable 객체인 튜플을 통해 조금 더 자세히 살펴보겠습니다. 위의 코드는 전역에서 Immutable한 객체인 튜플을 변경해보는 예제입니다. 기존의 a에 담긴 (2, 3, 4) 객체의 레퍼런스와 요소 10을 추가하는 작업을 진행한 a에 담긴 (2, 3, 4, 10) 객체의 레퍼런스는 다릅니다.(id()는 객체의 레퍼런스를 리턴해주는 함수입니다!) 튜플은 변경불가능한 객체이기 때문에 요소 추가 작업을 해도 기존의 튜플 인스턴스에 요소가 추가되는 것이 아니라, 추가할 요소가 포함된 새로운 튜플 인스턴스를 만들어 이를 변수가 가리키게 됩니다. 이러한 Immutable한 객체의 성질로 인해, 함수에 인자로 전달되는 모든 Immutable한 객체는 마치 Call by value처럼 동작하는 것입니다.
2. 변경가능한 객체(Mutable object)
def mutable_call(x): x.append(5) print('local:', x) b = [1, 2] mutable_call(b) # local: [1, 2, 5] print(b) # [1, 2, 5]
list, set, dict가 여기에 속합니다. Mutable한 객체가 함수 인자로 전달될 때는 함수 내부에서 매개변수의 내용을 변경하면 함수 바깥에서 인자로 전달한 변수의 객체도 변경됩니다. 마치 Call by reference처럼 동작합니다. (정확히 살펴보면, 'Mutable한 객체인 리스트 b에 요소 5를 추가한다는 것'은 b가 변경이 가능하기 때문에 새로운 객체를 생성하지 않고 기존 객체 b에 그대로 요소 5를 추가한다는 의미입니다.)
'마치 Call by reference처럼 동작한다'라고 말한 이유를 리스트를 통해 계속 살펴보겠습니다. 위 코드는 전역에서 Mutable한 객체인 리스트를 변경해보는 예제입니다. 리스트에 요소 10을 추가하는 작업을 하면, 기존에 a가 가리키고 있던 리스트에 10이 추가됩니다.(변경 전과 변경 후 a가 가리키는 레퍼런스의 차이가 없죠!) 즉, 변경가능한 객체는 말 그대로 변경이 가능하기 때문에 굳이 새롭게 인스턴스를 만들 필요가 없어서 기존의 객체에 변경을 진행합니다. 이러한 Mutable한 객체의 성질로 인해, 함수에 인자로 전달되는 모든 Mutable한 객체는 마치 Call by reference처럼 동작하는 것이죠.
이상으로 Call by assignment에 대해 간략하게 정리해봤습니다. Call by assignment는 'Everything is an object in Python' 패러다임에서 비롯된 파이썬만의 독특한 함수 전달 방식입니다. 처음에는 Call by assignment 자체에 초점을 두었었는데, 사실 Call by assignment는 모든 것이 객체인 파이썬에서 Mutable object와 Immutable object의 성질로 인해 자연스럽게 나타난 현상으로 해석하는 것이 바람직할 것 같습니다.참고문서
Effective Python 1 - call by assignment
Call by assignment, mutable, immutable, 파이썬 복사(Python Copy)'Programming Language > Python' 카테고리의 다른 글
[Python] 비동기 프로그래밍을 돕는 asyncio 라이브러리 (0) 2021.05.29 [Python] 데코레이터(Decorator) - 효과적 프로그래밍을 위하여 (0) 2021.05.18 [Python] 놓치기 쉬운 개념들 정리 (0) 2021.04.15 [Python] 얼핏 헷갈리는 소소한 용어들 (0) 2021.04.15 [Python Programming 기초] # Class(클래스)와 Object(객체) : 개념 (0) 2020.11.18