Python 함수 객체: 함수도 하나의 객체다

Ad Placeholder

Python에서는 함수도 숫자나 문자열처럼 하나의 객체로 취급할 수 있습니다.

보통 함수를 생각하면 함수를 정의하고 호출하는 것을 먼저 떠올리지만, Python에서는 함수 자체를 변수에 저장하거나 다른 함수의 인자로 전달하거나 리스트와 딕셔너리에 넣는 것도 가능합니다.

이때 중요한 개념이 바로 함수 객체(Function Object)입니다.

함수도 객체다

먼저 간단한 함수를 만들어 보겠습니다.

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

일반적으로는 다음과 같이 함수를 호출합니다.

greet()

하지만 greet 뒤에 괄호를 붙이지 않고 사용하면 이야기가 달라집니다.

print(greet)

이때 greet는 함수를 실행하는 것이 아니라 함수 객체 자체를 가리킵니다.

즉 다음 두 표현은 서로 다릅니다.

greet
greet()

greet는 함수 객체이고, greet()는 그 함수 객체를 호출하여 실행하는 것입니다.

이 차이는 함수 객체를 이해할 때 가장 먼저 알아야 할 부분입니다.

함수 객체를 변수에 저장할 수 있다

Python에서는 함수 객체를 다른 변수에 저장할 수 있습니다.

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


hello = greet

이제 hello를 통해서도 함수를 실행할 수 있습니다.

hello()

결과:

안녕하세요

hello에 함수의 실행 결과가 저장된 것이 아닙니다.

hello가 greet라는 함수 객체를 가리키게 된 것입니다.

따라서 다음과 같이 확인할 수도 있습니다.

print(hello is greet)

결과:

True

두 변수가 같은 함수 객체를 가리키고 있기 때문입니다.

함수 이름과 함수 호출은 다르다

함수 객체를 이해하려면 함수 이름과 함수 호출을 구분하는 것이 중요합니다.

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

다음은 함수 객체를 가리킵니다.

add

반면 다음은 함수를 실행합니다.

add(10, 20)

그리고 실행 결과인 30이 반환됩니다.

result = add(10, 20)

print(result)

결과:

30

즉,

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

이 차이를 이해하면 이후에 함수를 다른 함수에 전달하는 코드를 훨씬 쉽게 이해할 수 있습니다.

함수의 타입 확인하기

함수도 객체이기 때문에 type()을 사용하여 타입을 확인할 수 있습니다.

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


print(type(greet))

결과는 다음과 같은 형태입니다.

<class 'function'>

즉 greet는 function 타입의 객체입니다.

Python에서 숫자도 객체이고 문자열도 객체인 것처럼 함수 역시 객체로 존재합니다.

함수 객체를 리스트에 저장할 수 있다

함수 객체는 리스트와 같은 자료구조에 저장할 수도 있습니다.

def hello():
    print("Hello")


def bye():
    print("Bye")


functions = [hello, bye]

리스트의 요소를 꺼내서 호출하면 해당 함수가 실행됩니다.

functions[0]()
functions[1]()

결과:

Hello
Bye

여기서 리스트에는 함수의 실행 결과가 저장된 것이 아니라 함수 객체 자체가 저장되어 있습니다.

다음과 같은 차이가 있습니다.

functions = [hello, bye]

함수 객체를 저장하는 경우입니다.

반면,

functions = [hello(), bye()]

이렇게 작성하면 함수를 먼저 실행하고 그 결과를 리스트에 저장하게 됩니다.

따라서 함수 객체를 다룰 때는 ()의 유무가 중요합니다.

함수 객체를 딕셔너리에 저장할 수도 있다

함수 객체는 딕셔너리에도 저장할 수 있습니다.

예를 들어 연산 종류에 따라 실행할 함수를 선택하도록 만들 수 있습니다.

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


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


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

이제 문자열을 이용해 원하는 함수를 가져올 수 있습니다.

result = operations["add"](10, 3)

print(result)

결과:

13

operations["add"]가 add 함수 객체를 가져오고, 뒤의 ()가 그 함수를 호출하는 구조입니다.

이런 방식은 실행할 동작을 상황에 따라 선택해야 할 때 유용합니다.

함수 객체를 다른 함수의 인자로 전달하기

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

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


def execute(func):
    return func()

이제 greet를 execute()에 전달할 수 있습니다.

result = execute(greet)

print(result)

결과:

안녕하세요

여기서 중요한 부분은 execute(greet)입니다.

greet()가 아니라 greet를 전달했습니다.

execute(greet)

이렇게 하면 함수 객체가 execute()의 func 매개변수로 전달됩니다.

그리고 내부에서

func()

를 통해 전달받은 함수를 실행합니다.

이처럼 함수를 다른 함수에 전달하는 방식은 Python에서 매우 자주 사용됩니다.

함수를 반환할 수도 있다

함수 객체는 함수의 반환값으로 사용할 수도 있습니다.

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


def get_function():
    return greet

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

func = get_function()

print(func())

결과:

안녕하세요

동작을 순서대로 보면 다음과 같습니다.

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

즉 함수가 단순히 값을 반환하는 것뿐만 아니라 다른 함수를 반환하는 것도 가능합니다.

함수 객체에는 정보도 들어 있다

함수 객체에는 함수와 관련된 여러 속성이 있습니다.

대표적으로 __name__을 사용하면 함수의 이름을 확인할 수 있습니다.

def greet():
    """인사를 출력하는 함수"""
    print("안녕하세요")


print(greet.__name__)

결과:

greet

함수에 작성한 설명인 독스트링은 __doc__으로 확인할 수 있습니다.

print(greet.__doc__)

결과:

인사를 출력하는 함수

이처럼 함수는 단순히 실행할 코드만 가지고 있는 것이 아니라 함수 이름이나 설명 등의 정보도 가지고 있는 객체입니다.

함수 객체를 사용하는 간단한 예제

함수 객체의 특징을 하나의 예제로 묶어보겠습니다.

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()는 어떤 계산을 할지 직접 결정하지 않습니다.

대신 add 또는 multiply라는 함수 객체를 전달받아 실행합니다.

이렇게 만들면 같은 calculate() 함수를 다양한 함수와 조합할 수 있습니다.

함수 객체에서 기억해야 할 것

함수 객체를 이해할 때는 다음 세 가지를 기억하면 됩니다.

첫째, Python에서 함수는 하나의 객체입니다.

둘째, 함수 객체를 변수나 리스트, 딕셔너리에 저장할 수 있습니다.

셋째, 함수 객체를 다른 함수의 인자로 전달하거나 반환할 수 있습니다.

특히 다음 두 표현의 차이는 꼭 기억해두는 것이 좋습니다.

greet
greet()

첫 번째는 함수 객체를 가리키고, 두 번째는 함수를 호출합니다.

마무리

Python의 함수는 단순히 호출해서 사용하는 코드 묶음만을 의미하지 않습니다.

함수 자체가 하나의 객체이기 때문에 변수에 저장하거나 자료구조에 넣을 수 있고, 다른 함수에 전달하거나 함수에서 반환하는 것도 가능합니다.

이러한 특징을 이해하면 이후에 등장하는 콜백 함수, 데코레이터, 람다 함수 등의 동작도 훨씬 쉽게 이해할 수 있습니다.

다음 글에서는 여기서 한 단계 더 나아가 함수를 값처럼 다룰 수 있는 객체의 특징인 일급 객체(First-Class Object)에 대해 알아보겠습니다.

jiji

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

Ad Placeholder
Scroll to Top