5-5 람다 함수: 간단한 익명 함수 활용

5-5 람다 함수: 간단한 익명 함수 활용

← 목차로 돌아가기

썸네일

파이썬에는 `def` 키워드를 사용하여 이름을 부여하는 일반 함수 외에, 짧고 간결한 기능을 수행하는 ‘익명 함수’가 있습니다. 바로 람다(lambda) 함수입니다. 람다 함수는 코드를 더욱 효율적이고 가독성 있게 만들 때 유용하게 활용됩니다.

람다 함수란 무엇인가요?

람다 함수는 이름을 가지지 않는, 한 줄로 정의되는 간결한 함수입니다. 파이썬에서 `def` 키워드로 정의하는 일반 함수와 달리, `lambda` 키워드를 사용하여 즉석에서 정의하며, 주로 간단한 연산이나 로직을 필요로 할 때 사용합니다. ‘익명 함수’라는 이름처럼, 함수를 정의하는 동시에 사용하는 경우가 많습니다.

일반 함수의 기본 형태가 `def 함수명(매개변수): return 표현식`이라면, 람다 함수의 형태는 `lambda 매개변수: 표현식`으로 훨씬 간결합니다. 결과적으로 하나의 표현식만 가질 수 있다는 특징 때문에 복잡한 로직보다는 간단한 처리에 적합합니다.

왜 람다 함수를 사용해야 할까요?

람다 함수는 작은 기능을 즉석에서 정의하여 코드 가독성을 높이고 불필요한 함수 정의를 줄일 때 유용합니다. 저는 데이터 분석 시 리스트딕셔너리 데이터를 처리하거나 Pandas 라이브러리의 `apply()` 메서드와 함께 간단한 데이터 변환에 람다 함수를 자주 활용합니다. 이는 일반 함수를 따로 정의하는 것보다 코드를 훨씬 깔끔하게 유지할 수 있기 때문입니다.

특히 `map()`, `filter()`, `sorted()`와 같은 고차 함수(higher-order functions)와 함께 사용할 때 람다 함수의 진가가 발휘됩니다. 이러한 함수들은 인자로 다른 함수를 받는데, 이때 람다 함수를 사용하면 필요한 기능을 한 줄로 정의하여 전달할 수 있어 코드의 흐름을 방해하지 않고 직관적으로 이해할 수 있습니다. 굳이 이름을 붙일 필요가 없는 일회성 기능에 적절하다고 볼 수 있습니다.

람다 함수 정의 및 활용법

`lambda` 키워드 뒤에 매개변수를 지정하고 콜론(`:`) 뒤에 한 줄짜리 표현식을 작성하여 람다 함수를 정의합니다. 람다 함수는 아래와 같이 정의하고 일반 함수처럼 호출할 수 있습니다.

# 두 숫자를 더하는 람다 함수 정의 및 사용
add = lambda x, y: x + y
print(f"두 숫자를 더한 결과: {add(5, 3)}") # 출력: 두 숫자를 더한 결과: 8

# 어떤 숫자를 제곱하는 람다 함수
square = lambda num: num * num
print(f"숫자 7의 제곱: {square(7)}") # 출력: 숫자 7의 제곱: 49

# 조건부 표현식을 포함한 람다 함수
is_even = lambda num: "짝수" if num % 2 == 0 else "홀수"
print(f"숫자 4는 {is_even(4)}") # 출력: 숫자 4는 짝수
print(f"숫자 9는 {is_even(9)}") # 출력: 숫자 9는 홀수

위 예시에서 볼 수 있듯이, 람다 함수는 여러 개의 매개변수를 가질 수도 있고, 조건부 표현식 (`if-else`)도 포함할 수 있습니다. 하지만 `if-else` 문 자체를 사용하는 것이 아니라, 한 줄의 표현식 내에서 결과를 반환하는 ‘조건부 표현식’ 형태여야 한다는 점을 기억해야 합니다. 조건문의 심화된 형태라고 이해하시면 좋습니다.

내장 함수와 람다 함수의 시너지

파이썬의 `map()`, `filter()`, `sorted()`와 같은 고차 함수들은 람다 함수와 결합하여 데이터를 효율적으로 처리할 수 있습니다. 이들은 모두 함수를 인자로 받아 리스트나 다른 시퀀스 데이터를 처리하는 데 사용됩니다. 일반 함수를 사용하는 경우 함수 정의와 호출 과정이 다소 길어질 수 있지만, 람다 함수를 활용하면 코드를 간결하게 유지할 수 있습니다.

map() 함수와 람다

`map()` 함수는 시퀀스의 각 요소에 함수를 적용하고 그 결과를 반환합니다.

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

# 각 숫자를 제곱하는 람다 함수를 map()에 적용
squared_numbers = list(map(lambda x: x * x, numbers))
print(f"제곱된 숫자들: {squared_numbers}") # 출력: 제곱된 숫자들: [1, 4, 9, 16, 25]

filter() 함수와 람다

`filter()` 함수는 시퀀스의 각 요소에 함수를 적용하여 참(True)인 경우만 걸러냅니다.

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# 짝수만 걸러내는 람다 함수를 filter()에 적용
even_numbers = list(filter(lambda x: x % 2 == 0, numbers))
print(f"짝수만 필터링: {even_numbers}") # 출력: 짝수만 필터링: [2, 4, 6, 8, 10]

sorted() 함수와 람다

`sorted()` 함수는 `key` 인자에 람다 함수를 전달하여 특정 기준으로 데이터를 정렬할 수 있습니다. 이는 복잡한 데이터 구조에서 특히 유용합니다.

students = [
    {'name': 'Alice', 'score': 85},
    {'name': 'Bob', 'score': 92},
    {'name': 'Charlie', 'score': 78}
]

# 'score'를 기준으로 정렬하는 람다 함수를 key에 적용
sorted_students_by_score = sorted(students, key=lambda student: student['score'])
print(f"점수별 정렬: {sorted_students_by_score}")
# 출력: 점수별 정렬: [{'name': 'Charlie', 'score': 78}, {'name': 'Alice', 'score': 85}, {'name': 'Bob', 'score': 92}]

# 'name'의 길이(len)를 기준으로 정렬하는 람다 함수를 key에 적용
sorted_students_by_name_length = sorted(students, key=lambda student: len(student['name']))
print(f"이름 길이별 정렬: {sorted_students_by_name_length}")
# 출력: 이름 길이별 정렬: [{'name': 'Bob', 'score': 92}, {'name': 'Alice', 'score': 85}, {'name': 'Charlie', 'score': 78}]

람다 함수의 한계와 주의사항

람다 함수는 간결하지만 복잡한 로직이나 여러 줄의 코드가 필요할 때는 일반 함수(`def`)를 사용하는 것이 좋습니다. 람다 함수는 오직 하나의 표현식만 포함할 수 있으며, 이 표현식의 결과가 자동으로 반환됩니다. 따라서 다음과 같은 작업은 람다 함수로 할 수 없습니다.

  • 여러 줄의 명령문 (예: `if-elif-else` 블록, `for` 루프).
  • 변수 할당 (`=`)과 같은 문장.
  • `print()` 함수처럼 반환값이 아닌 부수 효과를 일으키는 문장.

또한, 람다 함수는 이름을 가지지 않으므로 독스트링(docstring)을 가질 수 없으며, 디버깅 시 스택 트레이스(stack trace)에서 익명으로 표시되어 추적이 다소 어려울 수 있습니다. 초기에 GUI 개발 시 Tkinter 이벤트 핸들러에 람다를 무리하게 적용하려다 코드가 복잡해져 결국 일반 함수로 되돌린 경험이 있습니다. 간결함이 오히려 가독성을 해칠 수 있음을 깨달았던 순간입니다.

자주 하는 실수와 해결 방안

람다 함수는 단일 표현식만 허용하므로, 여러 줄의 로직이나 할당문, `print()` 함수 등을 사용하면 오류가 발생합니다.

  • 실수 1: 람다 함수 내에서 변수 할당 시도
    # 잘못된 예시: 람다 함수 내에서 할당문 사용
    # my_lambda = lambda x: y = x * 2 # SyntaxError 발생

    해결책: 람다 함수는 표현식만 허용하므로, 할당문은 사용할 수 없습니다. 이 경우 일반 함수를 사용해야 합니다.

  • 실수 2: 람다 함수 내에서 `print()` 함수 사용 시도
    # 잘못된 예시: 람다 함수 내에서 print() 사용
    # my_lambda = lambda x: print(x * 2) # 람다는 표현식의 결과를 반환해야 합니다.

    해결책: `print()` 함수는 `None`을 반환하므로, 람다 함수의 목적에 맞지 않습니다. 디버깅 목적이라면 외부에서 호출하거나 일반 함수를 사용하십시오.

  • 실수 3: 너무 복잡한 로직을 람다 함수로 구현하려 할 때

    람다 함수가 너무 길어지거나 이해하기 어렵다면, 이미 한계를 넘어선 것입니다.

    해결책: 가독성이 떨어지는 복잡한 람다 함수는 과감히 일반 함수(`def`)로 전환하여 여러 줄에 걸쳐 로직을 명확하게 표현하는 것이 좋습니다. 유지보수 측면에서 훨씬 유리합니다.

마무리하며

이번 챕터에서는 파이썬의 강력하고 간결한 기능 중 하나인 람다 함수에 대해 자세히 알아보았습니다. 람다 함수는 코드 한 줄로 간단한 기능을 정의하고 활용할 수 있는 익명 함수입니다. 특히 `map()`, `filter()`, `sorted()`와 같은 고차 함수와 함께 사용할 때 그 유용성이 극대화됩니다.

람다 함수는 언제나 만능 해결책은 아니며, 복잡한 로직이나 여러 줄의 코드가 필요할 때는 일반 함수를 사용하는 것이 바람직합니다. 상황에 맞춰 적절하게 람다 함수를 활용하는 것이 좋은 파이썬 코드를 작성하는 핵심입니다. 다음 챕터에서는 모듈과 패키지를 통해 코드를 더욱 체계적으로 구조화하는 방법을 살펴보겠습니다.

자주 묻는 질문 (FAQ)

Q1: 람다 함수는 `def` 함수와 어떻게 다른가요?

A: 람다 함수는 이름이 없는 ‘익명’ 함수이며, 오직 하나의 표현식만을 포함할 수 있습니다. 반면 `def` 함수는 이름을 가지며 여러 줄의 문장과 복잡한 로직을 처리할 수 있습니다. 람다 함수는 주로 코드 내에서 즉석으로 사용되는 간단한 기능을 정의할 때 적합합니다.

Q2: 람다 함수는 항상 더 좋은가요?

A: 아닙니다. 람다 함수는 간결하지만, 가독성을 해칠 만큼 복잡해지거나 여러 줄의 로직이 필요할 때는 `def` 함수가 더 좋습니다. 람다 함수는 짧고 명확한 한 줄짜리 기능에 사용하는 것이 최적의 활용법입니다.

Q3: 람다 함수는 몇 개의 매개변수를 가질 수 있나요?

A: 람다 함수는 0개부터 여러 개의 매개변수를 가질 수 있습니다. 일반 함수와 마찬가지로 필요한 만큼의 매개변수를 지정할 수 있지만, 매개변수가 너무 많아지면 람다 함수의 간결성이 떨어지므로 `def` 함수를 고려하는 것이 좋습니다.

참고 자료

  1. [1] Python 공식 튜토리얼 — 제어 흐름 도구와 함수 정의 — https://docs.python.org/ko/3/tutorial/controlflow.html
  2. [2] Python 용어집 — https://docs.python.org/ko/3/glossary.html

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다