Python/Python 기초

[Python] 함수 심화 - 고차함수

죵욜이 2024. 12. 10. 22:17

함수는 크게보면 4가지로 구분할 수 있다.

  • 매개변수 있고, 없고
  • 리턴값 있고, 없고

이경우인데 예시를 보며 살펴보자


1. 매개변수와 반환값이 없는 함수

  • 이 함수는 매개변수를 받지 않으며, 값을 반환하지도 않습니다.
def 안녕():
    print("안녕하세요!")

안녕()  # 출력: 안녕하세요!

2. 매개변수는 있지만 반환값이 없는 함수

  • 이 함수는 외부로 값을 반환하지 않지만, 입력된 매개변수로 어떤 작업을 수행합니다.
def 더하기(a, b):
    print(a + b)

더하기(3, 5)  # 출력: 8

3. 매개변수가 없고 반환값이 있는 함수

  • 이 함수는 매개변수는 받지 않지만, 계산이나 작업 후 결과값을 반환합니다.
def 랜덤_수():
    import random
    return random.randint(1, 100)

print(랜덤_수())  # 출력: 1과 100 사이의 랜덤한 숫자

4. 매개변수와 반환값이 모두 있는 함수

  • 이 함수는 매개변수를 받아서 계산을 한 뒤 결과를 반환합니다.
def 곱셈(a, b):
    return a * b

result = 곱셈(3, 4)  # result에 12가 저장됩니다.
print(result)  # 출력: 12

이렇게 4가지 유형의 함수로 나눌 수 있습니다. 각각은 함수가 처리하는 입력 출력에 따라 다르게 설계됩니다.


일급 함수 (First-Class Function)

일급 함수는 함수가 다른 데이터 타입처럼 완전히 동등하게 취급되는 프로그래밍 개념을 의미

 

 

일급 함수의 특성

1. 변수에 할당 가능

def 인사():
    return "안녕하세요"

greet = 인사  # 함수 인사()를 변수 greet에 할당
print(greet())  # 출력: 안녕하세요

 

2. 함수의 인자로 전달 가능

def 실행(func):
    return func()

def 인사():
    return "안녕하세요"

print(실행(인사))  # 출력: 안녕하세요

 

3. 함수의 반환값으로 사용 가능

def 곱셈(a, b):
    return a * b

def 계산(func):
    return func(2, 3)

print(계산(곱셈))  # 출력: 6

 

4. 함수 내에서 동적으로 생성 가능

def 외부():
    def 내부():
        return "안녕하세요, 함수 안에서!"
    return 내부

func = 외부()  # 내부() 함수 반환
print(func())  # 출력: 안녕하세요, 함수 안에서!

일급 함수의 장점

 

  • 고차 함수 (Higher-Order Function): 함수를 인수로 받거나 반환하는 함수는 고차 함수라고 합니다. 일급 함수 덕분에 고차 함수를 쉽게 구현할 수 있습니다.
  • 함수형 프로그래밍: 일급 함수는 함수형 프로그래밍의 핵심 개념입니다. 이를 통해 함수들을 조합하고, 추상화하여 복잡한 로직을 간결하게 표현할 수 있습니다.
  • 유연성: 함수가 변수로 다뤄지기 때문에, 더 유연하고 동적으로 코드를 작성할 수 있습니다.

 


예시: 고차 함수 (Higher-Order Function)

함수를 인수로 받는 함수 또는 함수를 반환하는 함수를 구현할 수 있습니다.

def 두배(func):
    def 래핑(x):
        return func(x) * 2
    return 래핑

def 제곱(x):
    return x * x

두배_제곱 = 두배(제곱)
print(두배_제곱(3))  # 출력: 18 (3의 제곱은 9, 두배는 18)

위 예시에서 두배는 고차 함수로, 함수 제곱을 인수로 받아서 그 함수의 반환값을 두 배로 만드는 새로운 함수를 반환합니다.


다른 함수들은 뭐가 있을까?

 

lambda 함수

  • 람다함수는 간단한 함수를 만들 때 사용한다.
  • 짧고 간단한 함수를 한 줄로 작성할 때 유용
  • 주로 다른 함수에 인자로 전달될 때 많이 사용한다
# 일반 함수
def 더하기(a, b):
    return a + b

# 익명 함수 (lambda)
더하기_lambda = lambda a, b: a + b

print(더하기(3, 4))  # 출력: 7
print(더하기_lambda(3, 4))  # 출력: 7

클로저 함수 (Closure)

  • 내부 함수가 외부 함수의 변수에 접근할 수 있는 기능을 의미
  • 함수가 다른 함수의 로컬 변수를 참조할 수 있는 특성
def 외부(x):
    def 내부(y):
        return x + y
    return 내부

add_5 = 외부(5)  # 외부 함수에서 x=5 설정
print(add_5(3))  # 출력: 8 (x=5, y=3)

고차 함수 예시 : map, filter, reduce

파이썬에서 제공하는 내장 함수인 map() , filter() , reduce() 는 모두 고차 함수들이다

 

  • map() : 주어진 함수로 리스트의 각 항목을 처리합니다.
  • filter() : 주어진 함수의 조건을 만족하는 항목만 필터링합니다.
  • reduce() : 리스트의 항목을 하나의 값으로 축소합니다.

 

from functools import reduce

# map() 예시
numbers = [1, 2, 3, 4]
squared = map(lambda x: x**2, numbers)
print(list(squared))  # 출력: [1, 4, 9, 16]

# filter() 예시
even_numbers = filter(lambda x: x % 2 == 0, numbers)
print(list(even_numbers))  # 출력: [2, 4]

# reduce() 예시
total = reduce(lambda x, y: x + y, numbers)
print(total)  # 출력: 10 (1+2+3+4)

재귀 함수

  • 재귀는 함수가 자기 자신을 호출하는 것입니다.
  • 복잡한 문제를 작은 문제로 나누어 해결할 때 유용합니다.
# 팩토리얼 계산
def factorial(n):
    if n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(5))  # 120

지연 평가 (Lazy Evaluation)

  • 값이 실제로 필요할 때까지 계산을 미루는 방식
  • 제너레이터나 itertools 와 같은 라이브러리에서 이를 사용할 수 있다
import itertools

# 지연 평가: 처음 3개의 값만 필요
gen = itertools.count(1)  # 무한 시퀀스
print(next(gen))  # 출력: 1
print(next(gen))  # 출력: 2
print(next(gen))  # 출력: 3

이 경우 itertools.count() 는 무한히 값을 생성하지만, 필요한 만큼만 계산한다