Python 일급 객체(First-Class Object): 함수를 값처럼 사용하는 이유

Ad Placeholder

Python에서는 함수를 변수에 저장하거나 다른 함수의 인자로 전달하고, 함수에서 다른 함수를 반환할 수도 있습니다.

앞에서 살펴본 함수 객체에서 바로 이어지는 내용인데, 이런 특징을 가진 객체를 Python에서는 일급 객체(First-Class Object)라고 합니다.

특히 Python의 함수는 일급 객체이기 때문에 일반적인 값처럼 다양한 곳에서 사용할 수 있습니다.

일급 객체란?

일급 객체란 간단하게 말하면 프로그램에서 일반적인 값처럼 자유롭게 다룰 수 있는 객체를 의미합니다.

일급 객체의 대표적인 특징은 다음과 같습니다.

  • 변수에 할당할 수 있다.
  • 함수의 인자로 전달할 수 있다.
  • 함수에서 반환할 수 있다.
  • 자료구조에 저장할 수 있다.

Python의 함수는 이 조건들을 모두 만족합니다.

예를 들어 숫자는 변수에 저장할 수 있습니다.

number = 10

문자열도 변수에 저장할 수 있습니다.

name = "Python"

마찬가지로 함수도 변수에 저장할 수 있습니다.

def greet():
    print("안녕하세요")


hello = greet

이처럼 Python에서는 함수 역시 값처럼 다룰 수 있습니다.

1. 변수에 할당할 수 있다

일급 객체의 첫 번째 특징은 변수에 할당할 수 있다는 것입니다.

def greet():
    print("안녕하세요")


hello = greet

이제 hello를 호출하면 greet()와 동일하게 동작합니다.

hello()

결과:

안녕하세요

여기서 중요한 점은 greet()의 결과를 저장한 것이 아니라는 것입니다.

hello = greet

이 코드는 greet 함수 객체를 hello라는 변수에 할당합니다.

반면 다음 코드는 함수를 실행한 결과를 저장합니다.

hello = greet()

따라서 함수 객체 자체를 전달할 때는 ()를 붙이지 않습니다.

greet      → 함수 객체
greet()    → 함수 실행

2. 함수의 인자로 전달할 수 있다

일급 객체인 함수는 다른 함수의 인자로 전달할 수 있습니다.

def greet():
    return "안녕하세요"


def execute(func):
    return func()


print(execute(greet))

결과:

안녕하세요

execute(greet)에서 greet는 함수 객체로 전달됩니다.

그리고 execute() 내부의 func가 전달받은 함수를 가리키게 됩니다.

def execute(func):
    return func()

따라서 func()를 실행하면 원래 전달했던 greet()가 실행됩니다.

이런 구조는 특정 동작을 함수 외부에서 전달받아 실행해야 할 때 유용합니다.

여러 함수를 하나의 함수에 전달하기

함수 객체를 인자로 전달하는 특징을 활용하면 같은 함수에 다양한 동작을 전달할 수도 있습니다.

def add(a, b):
    return a + b


def multiply(a, b):
    return a * b


def calculate(func, a, b):
    return func(a, b)


print(calculate(add, 10, 20))
print(calculate(multiply, 10, 20))

결과:

30
200

calculate() 자체는 덧셈인지 곱셈인지 알 필요가 없습니다.

실제로 어떤 연산을 수행할지는 func로 전달된 함수가 결정합니다.

이런 방식으로 데이터와 동작을 분리할 수 있다는 것이 함수가 일급 객체인 것의 중요한 장점입니다.

3. 함수에서 반환할 수 있다

일급 객체는 함수에서 반환할 수도 있습니다.

Python에서는 함수가 다른 함수를 반환하는 것도 가능합니다.

def greet():
    return "안녕하세요"


def get_function():
    return greet

이제 get_function()을 호출하면 greet 함수 객체가 반환됩니다.

func = get_function()

print(func())

결과:

안녕하세요

동작을 정리하면 다음과 같습니다.

get_function()
      ↓
greet 함수 반환
      ↓
func에 저장
      ↓
func()
      ↓
"안녕하세요"

이처럼 함수가 다른 함수를 만들어 반환하거나 선택해서 반환하는 구조도 만들 수 있습니다.

4. 자료구조에 저장할 수 있다

함수는 리스트나 딕셔너리 같은 자료구조에도 저장할 수 있습니다.

예를 들어 여러 함수를 리스트에 넣을 수 있습니다.

def hello():
    print("Hello")


def bye():
    print("Bye")


functions = [hello, bye]

그리고 리스트에서 꺼낸 함수를 실행할 수 있습니다.

for func in functions:
    func()

결과:

Hello
Bye

딕셔너리를 이용하면 특정 이름에 함수를 연결하는 방식도 가능합니다.

def add(a, b):
    return a + b


def subtract(a, b):
    return a - b


operations = {
    "add": add,
    "subtract": subtract
}

이제 문자열을 기준으로 실행할 함수를 선택할 수 있습니다.

operation = "add"

result = operations[operation](10, 5)

print(result)

결과:

15

이런 구조는 프로그램의 동작을 상황에 따라 선택해야 할 때 활용할 수 있습니다.

일급 객체와 일반 객체의 차이

일급 객체라는 표현 때문에 특별한 종류의 객체라고 생각하기 쉽지만, 핵심은 객체를 어떻게 다룰 수 있느냐에 있습니다.

예를 들어 Python의 정수도 변수에 저장할 수 있습니다.

number = 10

함수도 변수에 저장할 수 있습니다.

def greet():
    print("Hello")


func = greet

정수는 리스트에 넣을 수 있습니다.

numbers = [10, 20, 30]

함수 역시 리스트에 넣을 수 있습니다.

functions = [greet]

즉 함수도 다른 값과 비슷한 방식으로 프로그램 안에서 전달하고 저장할 수 있습니다.

일급 객체라고 해서 모든 것을 동일하게 처리한다는 뜻은 아니다

일급 객체라는 말을 처음 접하면 함수가 숫자나 문자열과 완전히 동일하다고 생각할 수 있습니다.

하지만 정확하게는 값처럼 전달하고 저장할 수 있다는 의미에 가깝습니다.

함수는 실행할 수 있다는 고유한 특징이 있습니다.

def greet():
    return "Hello"
func = greet

여기서 func는 함수 객체이기 때문에 호출할 수 있습니다.

func()

반면 숫자는 호출할 수 없습니다.

number = 10

number()

이 코드는 오류가 발생합니다.

따라서 일급 객체라는 것은 객체의 모든 동작이 동일하다는 의미가 아니라, 변수 할당, 전달, 반환, 저장 등의 과정에서 일반적인 값처럼 취급할 수 있다는 의미입니다.

일급 객체와 함수 객체의 관계

앞에서 배운 함수 객체와 이번에 배운 일급 객체는 서로 연결되어 있습니다.

함수 객체는 말 그대로 함수 자체가 하나의 객체라는 개념입니다.

그리고 그 함수 객체를 변수에 저장하거나 함수의 인자로 전달하고, 반환하고, 자료구조에 저장할 수 있기 때문에 Python의 함수는 일급 객체라고 합니다.

정리하면 다음과 같습니다.

함수
 ↓
하나의 객체로 존재
 ↓
변수에 저장 가능
 ↓
인자로 전달 가능
 ↓
함수에서 반환 가능
 ↓
자료구조에 저장 가능
 ↓
일급 객체

일급 객체의 장점

함수가 일급 객체라는 특징은 프로그램을 유연하게 만드는 데 도움이 됩니다.

예를 들어 여러 동작 중 하나를 선택해야 하는 경우 조건문을 계속 작성하는 대신 함수를 전달하는 방식으로 처리할 수 있습니다.

def add(a, b):
    return a + b


def multiply(a, b):
    return a * b


def calculate(func, a, b):
    return func(a, b)

이제 어떤 함수를 사용할지만 전달하면 됩니다.

calculate(add, 10, 20)
calculate(multiply, 10, 20)

이런 구조는 함수의 재사용성을 높이고, 코드의 동작을 유연하게 구성하는 데 도움이 됩니다.

실제로 Python의 sorted() 같은 내장 함수에서도 함수를 인자로 전달하는 방식을 자주 볼 수 있습니다.

numbers = [3, 1, 5, 2]

result = sorted(numbers, key=abs)

print(result)

key=abs에서 abs 역시 함수 객체입니다.

sorted()가 정렬 과정에서 사용할 기준을 함수 형태로 전달받는 것입니다.

일급 객체와 콜백 함수

함수를 다른 함수의 인자로 전달하는 패턴을 이해하면 콜백 함수(callback function)라는 개념도 자연스럽게 연결됩니다.

예를 들어 다음 코드에서 greet는 execute()에 전달됩니다.

def greet():
    print("안녕하세요")


def execute(func):
    func()


execute(greet)

execute()가 전달받은 함수를 나중에 호출하는 구조입니다.

이처럼 함수를 다른 함수에 전달하고 필요한 시점에 실행하는 패턴을 콜백이라고 부릅니다.

일급 객체라는 특성이 있기 때문에 이러한 구조를 만들 수 있습니다.

마무리

Python에서 함수가 일급 객체라는 것은 단순히 어려운 개념처럼 보이지만, 핵심은 간단합니다.

함수를 일반적인 값처럼 저장하고 전달하고 반환할 수 있다는 것입니다.

다시 정리하면 Python의 함수는 다음과 같은 특징을 가집니다.

  • 변수에 할당할 수 있다.
  • 다른 함수의 인자로 전달할 수 있다.
  • 함수에서 반환할 수 있다.
  • 리스트나 딕셔너리 등에 저장할 수 있다.
  • 필요할 때 전달받은 함수를 호출할 수 있다.

앞에서 배운 함수 객체가 함수 자체가 객체라는 관점이었다면, 일급 객체는 그 함수 객체를 값처럼 자유롭게 다룰 수 있다는 관점입니다.

다음 글에서는 이 특징을 더욱 간결하게 표현할 수 있는 람다(lambda) 함수를 알아보겠습니다.

jiji

AI, Python, 생활정보와 정부 정책 정보를 쉽게 설명하는 정보 블로그입니다.

Ad Placeholder
Scroll to Top