[Python] 일급객체(First-Class Object)

Aiden·2022년 2월 14일
0
post-thumbnail

파이썬 뿐만 아니라 자바스크립트, Swift 를 공부하다보면 일급객체나 일급함수에 대해 자주 들어보았을 것이다.
이는 클로저(Closure) 와 데코레이터(Decorator) 를 이해하는데 핵심적인 개념이기 때문에 한 번쯤 정리하고 넘어가야겠다는 생각을 거듭 해왔었다.

따라서, 이번 포스팅에서는 일급객체와 일급함수의 개념을 살펴보고, 이후 클로저와 데코레이터에 대해 포스팅해볼 예정이다.


일급객체(First-Class Object)?

📌 다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체

  • Wikipedia 에서 발췌한 일급객체의 정의이다.

여기서, 일반적으로 적용 가능한 연산이란 데이터를 할당하거나 반환하고 전달하는 것을 의미한다.

즉, 변수나 데이터 구조에 할당이 가능하며, 리턴 값으로 반환할 수 있거나, 파라미터로 전달할 수 있다면,
그 객체는 일급객체이다.


이제 일급객체의 조건을 정리해볼 수 있다.

  • 변수 혹은 데이터 구조 안에 담을 수 있다.
  • 파라미터로 전달할 수 있다.
  • Return 값으로 사용할 수 있다.

위 세가지 조건을 만족한다면, 그 객체는 일급객체라고 부를 수 있을 것이다.

우리가 언어를 배울 때, 가장 먼저 학습하는 int float str list 와 같은 기본적인 객체들도 사실은 모두 일급객체인 것이다.


일급함수(First-Class Function)?

그렇다면 일급함수란 무엇일까?

앞서 살펴보았던 일급객체의 조건들을 만족하는 함수가 바로 일급함수이다.

사실, 파이썬이나 자바스크립트에서는 함수마저도 intfloat str 등과 같은 기본적인 변수들처럼 일급객체로 취급한다.

즉, 함수도 변수 혹은 데이터 구조 안에 담길 수 있으며, 파라미터로 전달될 수 있고, Return 값으로 사용될 수 있는 것이다.

아래에서 파이썬 예제들을 통해 함수가 실제로 각각의 조건들을 만족하는지 살펴보도록 하자.

1. 변수 혹은 데이터 구조 안에 담을 수 있다.

# add 함수 생성
def add(x, y):
	return x + y
    
# func 변수에 할당
func = add

# 함수를 변수에 할당할 수 있다.
print(add(1, 2))
print(func(1, 2))
print(add)
print(func)
# Result
3
3
<function add at 0x0000015CC35DF040>
<function add at 0x0000015CC35DF040>

위 코드블럭에서는 add 함수를 생성하고, func 에 담아주었다. 이후, func 를 호출해 파라미터를 넣고 결과를 확인해보니 add 와 동일하게 동작하는 모습을 확인할 수 있었다.

⛔ 메모리 주소를 확인해본 결과, 서로 같은 주소값을 가리키고 있다.

즉, 함수는 변수에 할당이 가능하다는 것을 알 수 있다.

# add 함수 생성
def add(x, y):
	return x + y

# sub 함수 생성
def sub(x, y):
	return x - y

# list 에 할당
calculator = [add, sub]

for i in calculator:
	print(i(3, 1))
# Result
4
2

여기서는 addsub 함수를 생성하고 calculator 리스트에 담아 반복문으로 호출해보았다.

함수는 변수 뿐만 아니라, 리스트와 같은 자료구조에도 할당이 가능하다는 것을 확인할 수 있었다.

2. 파라미터로 전달할 수 있다.

# square 함수 생성
def square(x):
	return x * x

# first_class 함수 생성
def first_class(func, nums):
	return [func(num) for num in nums]

nums = [1, 2, 3, 4, 5]

# first_class 함수 호출
print(first_class(square, nums))
# Result
[1, 4, 9, 16, 25]

위 코드블럭에서는 square 함수와 first_class 함수를 생성해주었다. 이후, first_class 함수의 파라미터로 square 함수와 리스트를 전달해 결과값을 확인해보았다.

결론적으로, square 함수는 리스트 내의 각 원소들에 대해 정상적으로 동작하였고, 함수는 다른 함수의 파라미터로 전달 가능하다는 것을 알 수 있었다.

3. Return 값으로 사용할 수 있다.

# greetings 함수 생성
def greetings(name):

	# inner 내부 함수 생성
	def inner():
    	print("Hello {}!".format(name))
    
    return inner

# greetings 함수 호출
# func 에 할당
func = greetings("Python")

# 객체 출력
print(func)

# func 호출
func()
# Result
<function greetings.<locals>.inner at 0x000001E6B18C1040>
Hello Python!

위 코드블럭에서는 greetings 함수를 생성하고, 그 안에서 inner 함수를 생성해주었다. 이렇게 함수 안에서 정의된 함수를 내부함수라 한다.
greetings 함수는 내부 함수인 inner 함수를 반환한다.

greetings 함수에 문자열을 파라미터로 넣고 호출 한 뒤 반환값을 func 변수에 할당해주었다. 이 때, func 를 출력해보면 greetings 함수 안의 inner 함수를 가리키고 있는 것을 확인할 수 있다.

즉, inner 함수는 greetings 함수의 반환값이므로, funcinner 함수 객체를 가리키고 있다고 볼 수 있다. 이는 앞서 1번 예제에서 살펴본 변수에 함수 객체를 할당할 수 있는 원리와 같다.

마지막 줄에서는 func 를 함수로 호출하고 inner 함수가 정상적으로 동작하는 모습을 확인할 수 있다.

결론적으로, 함수는 다른 함수의 Return 값으로 사용 가능하다는 것을 알 수 있었다.


지금까지 파이썬에서의 함수가 일급객체의 세 가지 조건을 모두 만족한다는 것을 예제를 통해 확인하였고, 이를 통해 파이썬은 일급함수를 지원하는 언어라는 사실을 알 수 있었다.

즉, 파이썬에서 함수는 일반적인 변수나 자료구조들과 같이 하나의 일급객체로 취급되는 것이다.

⛔ 일급객체와 일급함수를 독립적인 개념으로 생각할 필요는 없다. 일급함수도 결국 일급객체일 뿐이다.


다음 포스팅에서는 클로저(Closure) 에 대해 다룰 예정이다.

사실, 우리는 3 번 예제에서 이미 클로저를 경험했다.
3 번 예제를 다시 살펴보면,

func = greetings("Python")

위 구문에서 greetings 함수는 이미 수행되고 실행이 종료되었는데,

func()

func() 를 통해 정상적으로 "Python" 이 다시 불러와진 것을 알 수 있다.
과연 어떻게 "Python" 이라는 파라미터를 계속 기억할 수 있었을까?
이 해답은 클로저에서 찾을 수 있다.

0개의 댓글