본문 바로가기

PYTHON

[Python] 일급 함수(First Class Function)

1. 변수 등에 할당 가능

 

2. 함수 인수 전달 가능

 

3. 함수 결과로 반환 가능

 

 

위의 세가지 조건이 충족된다면 일급함수(First Class Function)이다.

 

 

 


1. 변수 등에 할당 가능

 

def factorial(n):
    if n == 1:
        return 1
    return n*factorial(n-1)

 

 

# 변수 할당
var_func = factorial

print('1 -', var_func)
print('2 -', var_func(5))

 

 

결과값

1 - <function factorial at 0x000001E2674F99D0>
2 - 120

 

위의 코드와 같이 함수를 정의한 후 변수(var_func)에 함수를 할당해서 여러가지 방식으로 사용 할 수 있습니다.

 

 

 


2. 함수 인수 전달 및 함수로 결과 반환(Higher-order Function = 고위함수)

 

print('1 -', map(var_func, range(1,10)))
print('2 -', list(map(var_func, range(1,10))))
print('3 -', list(map(var_func, filter(lambda x: x%2==0 , range(1,6)))))

 

결과값

1 - <map object at 0x0000025D61F764C0>
2 - [1, 2, 6, 24, 120, 720, 5040, 40320, 362880]
3 - [2, 24]

 

코드에서 사용된 map()함수는 두 번째 파라미터에(iterable가능한 객체여야 한다.) 첫 번째 파라미터(함수)를 적용한 결과를 원소로 갖는 iterable 객체를 반환한다.

 

 

이와같이 일급 함수가 있으면 함수형 프로그래밍이 가능하다.

그렇다면 함수형 프로그래밍의 특징 중 하나인 고위함수에 대해서 좀 더 알아보자.

 

 

고위함수는 함수를 인수로 받거나, 함수를 결과로 반환하는 함수다.

위에서 사용한 map() 함수도 고위함수이다. 그 밖에도 sorted() 함수가 있는데 key 파라미터로 함수를 전달받아 정렬할 각 원소에 적용한다.

 

아래의 코드를 보자.

 

 

fruits = ['apple', 'banana', 'strawberry', 'blueberry', 'melon']

print(sorted(fruits, key=len))

 

 

결과값

['apple', 'melon', 'banana', 'blueberry', 'strawberry']

위와 같이 단어의 길이순서로 정렬하기 위해 len()함수를 key파라미터에 전달하면 된다.

Parameter를 1개 받는 함수는 모두 key에 전달할 수 있다.

 

 

 

그 외에도 위해서 한번 사용했던 filter()와 같은 고위함수가 있다.

print(list(map(var_func, filter(lambda x: x%2 , range(1,6)))))

 

결과값

[1, 6, 120]

 

 

 

map(), filter()는 파이썬3의 빌트인 함수이지만, 지능형 리스트(Comprehending List)와 제너레이터 표현식이 소개된 후에 이 함수들의 중요성은 다소 떨어졌다. map()과 filter()는 제너레이터를 리턴하므로 제너레이터 표현식이 이 함수들을 대체할 수 있기 때문이다.

 

# Comprehending List 사용

print([var_func(i) for i in range(1,6) if i%2])

 

결과값

[1, 6, 120]

 

 

iterable한 객체의 원소들의 합계를 내릴 때 사용하던 reduce()는 sum() 함수로 대체할 수 있다.

 

from functools import reduce
from operator import add

print(reduce(add, range(1,11)))
print(sum(range(1,11)))

 

결과값

55
55

 


익명함수(lambda)

 

고위함수를 사용할 때 일회용 함수를 생성하는 게 편리할 때도 있다. lambda키워드는 파이썬 표현식 내에서 익명함수를 제공한다. 그러나 람다 함수의 본체는 순수한 표현식으로만 구성하도록 제한되어있다.

 

익명함수를 사용할 땐 가급적 주석을 사용하고, 익명함수를 사용하는 것 보단 함수를 사용하는 것들 PEP(Python Enhance Proposal)에서도 권장한다.

(이름이 없는 함수를 많이 사용하면 코드의 가독성이 떨어진다는 인식이 있다.)

 

print(reduce(lambda x, t: x+t, range(1,11)))

 

결과값

55

reduce()add()함수 대신 익명함수(lambda) 함수를 사용해도 똑같은 결과값이 출력된다.

 

 

 


Collable : 호출 연산자 -> 메소드 형태로 호출 가능한지 확인

 

 

import random

# 로또 추첨 클래스 선언
class LottoGame:
    def __init__(self):
        self._balls = [n for n in range(1,46)]
    
    def pick(self):
        random.shuffle(self._balls)
        return sorted([random.choice(self._balls) for n in range(6)])

    def __call__(self):
        return self.pick()

 

__call__() 메서드를 오버로딩을 통해 구현하면 모든 객체를 콜러블 타입으로 만들 수 있다.

즉, 함수처럼 동작을 할 수 있게 해준다.

 

game = LottoGame()

# 호출 가능 확인
print(callable(str), callable(list), callable(factorial), callable(54))
print(game.pick())
print(game())
print(callable(game))

 

결과값

True True True False
[4, 20, 21, 34, 34, 38]
[6, 15, 16, 16, 19, 32]
True

 

__call__() 메소드가 구현되어 있으므로 LottoGame타입의 객체는 호출가능하며, return 값은 _balls에서 꺼낸 원소가 된다.