[Python]파이썬다운 함수 만들기 - 함수형 프로그래밍

Jay·2023년 5월 29일
0
post-thumbnail

함수형 프로그래밍은 전역 변수나 어떠한 외부 상태(파일, DB, 네트워크 등 외부 리소스)를 수정하지 않고 연산 수행 목적의 함수 작성을 강조하는 프로그래밍 패러다임입니다. 파이썬에서 제공하는 함수형 기능은 순수 함수, 고차 함수, 람다 함수가 있습니다.

순수 함수

순수 함수를 이해하기 위해서 알아야할 개념이 있습니다. 결정론적/비결정론적 함수부수효과입니다. 이 두가지의 개념과 순수 함수가 무엇이며, 어떠한 장점이 존재하는지 알아보겠습니다.

결정론적/비결정론적 함수

결정론적 함수는 같은 인수에 대하여 항상 같은 결과값을 반환하는 함수입니다. 예를 들어 두 정수의 합을 구하는 add(a, b)가 있다고 가정해봅시다. 만약 a=10, b=5라는 인수로 add() 함수를 호출하면 호출하는 시점이나 환경에 따라 다른 값을 반환하는 것이 아닌 15를 항상 동일하게 반환할 것입니다.

비결정론적 함수는 이와 달리 동일한 인수가 함수로 전달되어도, 다른 결과값을 반환할 수 있는 함수입니다. 예를 들어 random.randint(1, 10)을 호출하면 함수는 1과 10 사이의 임의의 정수를 반환할 것입니다. 이와 같은 함수를 비결정론적 함수라고 합니다.

결정론적 함수의 이점은 같은 인자에 대한 호출 반환값이 같은 결과값을 보장하므로, 결과값을 캐시하여 사용할 수 있다는 점입니다. 결과를 캐시에 저장하여 후에 해당 함수가 다시 호출된다면 캐싱해둔 값을 사용할 수 있고, 반복되는 연산 없이 빠른 실행 속도를 구현할 수 있습니다. 이처럼 결정론적 함수의 특징으로 인하여 메모리 공간을 활용하여 빠른 실행 속도를 얻을 수 있는 것을 시간과 공간 간의 트레이드오프라고 합니다.

부수효과

부수효과(Side effect)는 함수가 자신의 코드와 지역 변수 바깥에 존재하는 프로그램의 부분에 미치는 모든 변화를 의미합니다. 아래의 코드와 함께 설명하도록 하겠습니다.

TOTAL = 10

def addToTotal(amount:int):
	global TOTAL
    TOTAL += amount
    return TOTAL

addToTotal() 함수는 입력받은 인자의 값만큼 전역 변수인 TOTAL에 값을 더하는 함수입니다. 이 함수는 함수 내부의 값이 아닌 외부의 TOTAL 값 변경시키는 부수효과를 가지고 있습니다. 이러한 부수효과는 전역변수 값의 변경뿐만 아니라, 파일의 업데이트나 삭제, 화면의 텍스트 출력, 데이터베이스 연결, 서버 인증 등 모든 함수 외부의 변경을 의미할 수 있습니다.

순수 함수는?

순수 함수는 위에서 설명한 부수효과가 없는 결정론적 함수를 의미합니다. 순수 함수로 함수를 작성하면 얻을 수 있는 여러 장점들이 존재합니다.

  • 외부 자원을 설정할 필요가 없으므로 단위 테스트에 적합하다.
  • 버그를 재현하기 쉽다.
  • 순수 함수는 다른 순수 함수를 호출할 수 있고, 동시에 순수 함수 상태를 유지할 수 있다.
  • 멀티스레드 프로그램에서 스레드 및 동시 실행에 안전하다.
  • 병렬 CPU 코어나 멀티스레드 프로그램에서 실행되는 경우 특정 순서에 맞춰 실행되어야 하는 외부 자원에 의존할 필요가 없다.

앞서 결정론적 함수는 시간과 공간간의 트레이드 오프가 가능하다고 설명하였습니다. 그외에도 순수 함수는 외부로부터 격리된 상태로 인하여 다양한 장점들을 지닙니다.

멀티스레드 프로그램에서 함수 외부의 환경을 변경하지 않으므로 동시 실행이 안전한 스레드가 안전(Thread safe)한 프로그램을 작성할 수 있습니다. 또한 같은 인자로 함수를 호출하면 같은 값을 반환한다는 것은 함수 외부의 환경에 영향을 받지 않는다는 것을 의미합니다. 이는 함수의 단위 테스트코드 작성이 용이하고, 버그가 발생해도 같은 인자를 넣어 호출하면 같은 버그를 반환하므로, 디버깅에도 용이하다는 점을 지니고 있습니다.

이와 같은 순수 함수의 장점으로 인해 개발자는 순수 함수를 작성할 줄 알아야하며, 많은 개발자들이 순수 함수로 코드를 작성하는 것을 권장하고 있습니다. 하지만 파이썬에서는 이러한 순수 함수 작성을 강제할 수 있는 방법은 없으며 순전히 개발자가 유의하며 작성해야 합니다. 이러한 순수 함수를 작성하기 위해서는 전역 변수 사용을 피하고, 파일, 인터넷, 난수 등의 외부자원과의 상호작용을 줄이며 프로그램을 작성해야 합니다.



고차원 함수

고차원 함수는 다른 함수를 인수로 넘기거나 반환할 수 있는 함수를 의미합니다.

def callItTwice(func, *args, **kwargs):
	func(*args, **kwargs)
    func(*args, **kwargs)

callItTwice() 함수는 func 파라미터로 전달받은 어떤 함수에 대해서도 동작합니다. 파이썬에서 함수는 일급 객체이므로, 여느 다른 객체와 성질이 같습니다. 즉 함수를 변수에 저장하거나 인수로 전달하거나 반환값으로도 사용할 수 있으므로 위와 같이 함수를 인수로 전달하여 다른 함수 내부에서 호출하거나, 함수를 반환하는 것도 가능하게 됩니다.



람다 함수

람다 함수익명 함수 또는 이름 없는 함수라고 불립니다. 함수명이 정의되지 않고, 코드가 오직 하나의 return문으로 구성된 단순화된 함수입니다. 이러한 람다 함수는 주로 다른 함수에 인수로 전달할때 많이 사용됩니다. 람다 함수의 정의 방법은 아래와 같습니다.

someFunction = lambda 인자: (리턴할 값 정의)

# 직사각형의 가로, 세로를 통해 둘레를 구하는 람다함수
getRectangleParimeter = lambda rect: (rect[0]*2) + (rect[1]*2))

getRectangleParimeter([4, 10])		# returns 28

람다 함수는 다른 함수 호출에 필요한 함수를 정의하고 전달하는 인수 역할을 수행하는데 도움이 됩니다. 예를 들어 파이썬의 sorted() 함수에는 정렬 기준 함수를 지정할 수 있는 key 파라미터가 존재합니다. 이 key 파라미터를 통해 특정 함수의 결과값에 따라 정렬이 이루어지도록 함수를 호출할 수 있습니다.

rects = [[10, 2], [3, 6], [2, 4], [3, 9], [10, 7], [9, 9]] # 직사각형의 두 변
sorted(rects, key=lambda rect: (rect[0]*2) + (rect[1]*2))	# 직사각형의 둘레를 기준으로 정렬하도록 람다함수 구현

이와 같은 람다 함수를 통해 별도의 함수 정의 없이 한 줄의 코드로 함수를 인자로 전달할 수 있습니다.



0개의 댓글