Chapter 5. 함수/람다 프로그래밍

Python은 기존의 주류 언어들과 마찬가지로 함수와 객체를 지원합니다. Iron Python의 경우에도 당연히 이것이 가능합니다. 하지만 혼동하기 쉬운 점이 있는데, IronPython은 원래 “전역 (Global)”의 개념이 존재하지 않는 .NET 프레임워크의 특성을 간단히 무시하고 원래 Python의 특징을 흉내냅니다. 나중에 다룰 IronPython을 .NET Application에 Integration하는 단계에서 이것의 진짜 내막을 정확히 볼 수 있게 됩니다.


이러한 특징은 Visual Basic .NET의 모듈과 비슷한 원리인데, Visual Basic .NET의 모듈도 엄격히 따지면 보통의 클래스이지만 모듈의 이름을 애써 지정할 필요 없이 마치 전역 멤버처럼 사용하는 것이 가능한 이유가 Visual Basic 6.0의 특성을 흉내낸 것이기 때문입니다. 결론적으로 MSIL 코드에서는 전체 이름을 모두 기입해줍니다.


오늘 Chapter에서는 함수를 간단히 정의하고 사용하는 방법에 대해서 살펴보기로 합니다. 그리고 후반부에서는 C# 3.0에서도 도입이 거론되고 있는 람다에 대해서도 파이썬을 통해 보기로 합니다. 파이썬의 경우 람다는 실제로 사용하는 정규 문법입니다.


IronPython 콘솔을 켜고 다음과 같이 입력하도록 합니다.


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


구조는 너무나도 간결합니다. a와 b라는 것은 짐작이 가능합니다. 바로 함수의 매개 변수가 되는것이지요. 하지만 C#이나 VB.NET과는 달리 상당히 생략된 것이 많음을 알 수 있습니다. 하지만 이상하게 생각할 필요는 없습니다. 왜냐면, 우리는 목적에 맞는 프로그램을 온전히 구현하기 위한 것이 목표가 아니라 스크립트 언어의 특성에 맞는 프로그램을 표현 (Illustration)하기 위함이므로 이정도면 충분한 것입니다.


일단 a와 b라는 각각의 매개 변수에 대한 형식은 따로 지정하지 않았습니다. 즉 a와 b는 어떤 형식이든 대입이 가능함을 뜻합니다. 그리고 add라는 함수에 반환 형식을 지정하지 않았습니다. return 문 또는 뒤에 나올 yield 문 그 자체의 용법과 그것들이 다루는 데이터 형식에 따라서 함수의 반환 형식이 자동으로 결정될 수 있고 정확히 알 수 없는 경우에는 일반화된 형식으로 자동으로 결정하여 줄 것입니다.


위의 add 함수를 호출하는 방법 역시 간단합니다.


print add(1, 3)
print add(“hello “, “world “)


첫 번째의 경우 숫자 4를 반환할 것입니다. 두 번째의 경우에도 Concatenation 처리가 된 문자열이 반환될 것입니다. 두 가지 동작 모두 유효한 것입니다.


이번에는 재귀호출을 사용하는 예를 다루어보도록 하겠습니다. 팩토리얼을 구하는 함수를 프로그래밍해보면 좋겠지요. ^^


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


기본 알고리즘에 대해서는 따로 설명하지 않겠습니다. 당연한 이야기이지만 재귀 호출이 가능함을 보이고 있습니다.


이번에는 yield 키워드에 대하여 살펴보도록 하겠습니다.


def one_to_three():
  yield 1
  yield 2
  yield 3


yield 키워드는 C# 2.0의 것과 완전히 같은 용법을 제공합니다. 다만 return 키워드를 더 쓰지 않고 yield 문 하나만을 사용합니다.


그리고 함수를 프로그래밍하면서 필요한 것이 하나 더 있는데, 바로 함수의 문서화 작업입니다. 간단하지만 습관으로 두시는게 좋겠지요. Iron Python은 따로 문서화 문자열을 두지 않으면 자동으로 함수의 시그니처 (함수의 반환 형식과 매개 변수 목록, 함수의 이름과 같은 정보)를 생성하여 문서화에 반영하지만 이것을 직접 변경할 수도 있습니다.


def one_to_three_v2():
  “이곳에 설명문을 달아놓으면 됩니다.”
  yield 1
  yield 2
  yield 3


첫 줄에 지정한 문자열이 바로 문서화 문자열이 됩니다. 이것을 확인해 보기 위하여 두 가지 방법을 쓸 수 있는데 하나는 doc 프로퍼티를 직접 조회하는 것이고 또 하나는 help() 내장 함수를 이용하는 것입니다.


help(one_to_three_v2)
print one_to_three_v2.doc


help 내장 함수의 경우 좀 더 정리된 모습을 보여줍니다. 두 번째 방식도 가능한 것이므로 참고하시기 바랍니다.


오늘의 마지막 순서로 람다에 대하여 살펴보기로 합니다. 람다는 앞서 간단한 설명을 통해 언급하였듯이 C# 3.0에서 도입하고자 하는 람다와 유사한 것입니다. 람다는 한 줄에 표현이 가능한 수식을 함수로 만들어줍니다. 다음의 예를 살펴보도록 하지요.


(lambda x, y: x ** y)(10, 3)


위와 같이 구문을 입력하면 10의 3승 값인 1000이 반환됩니다. 간단히 분석해보도록 하지요. x와 y는 함수에서처럼 매개 변수를 뜻합니다. 그리고 : 기호 다음에 나오는 것이 수식이 됩니다. 람다는 값을 반환하는 작업 등은 전혀 하지 않습니다. 하지만, “평가”가 가능한 식 그 자체가 반환값이 됩니다.


일반적으로 모든 수식은 반환값이 자동으로 산출되는 “평가”가 가능한 형태입니다. 그리고 반환값이 있는 모든 종류의 함수들을 포함하여 읽기가 가능한 프로퍼티, 상수, 변수 등도 “평가”가 가능한 형태입니다. 이 두 가지를 모두 활용하더라도 반환값을 만들어낼 수 있는 것도 가능합니다. 더 나아가, 람다 자체는 어떤 값을 분명히 반환한다는 일종의 규약을 가지고 있기 때문에 람다 안에 람다를 집어넣는 중첩도 가능합니다.


람다는 저장해두었다가 필요할 때 재사용할 수 있습니다. 위의 식을 임의의 함수 o로 받아봅니다.


o = lambda x, y: x ** y
o(10, 3)


방금전과 마찬가지의 결과가 나타나게 됩니다. 이번엔 좀 더 나아가 람다 안에 람다를 집어넣는 중첩의 한 예를 보겠습니다.


(lambda x, y: (lambda z: z + 1)(x) ** y)(9, 3)


실용적으로 보이지는 않지만 가능한 예임을 들기 위하여 다소 복잡한 코드를 써보았습니다. 차례대로 따라가보면 쉽습니다. 안쪽의 람다부터 살펴보도록 하지요.


안쪽의 람다는 z라는 매개 변수를 받고 z에 1을 더하는 계산을 합니다. 함수 정의에 이어서 곧바로 호출을 하는데 여기에 들어갈 값은 바깥쪽의 람다의 x라는 매개 변수입니다. 즉, x에 1을 더한 값을 반환합니다. 그리고 이렇게 나타난 값에 y승 연산을 시키도록 합니다. 이것이 바깥 람다가 됩니다. 곧 이어, 바깥 람다 정의에 이어 호출에 들어가는데 인수로 9와 3이 주어집니다. 결과적으로 9는 1을 더하여 10이 되고 10의 3승을 계산합니다. 즉, 1000이 반환되겠지요.


오늘 강좌도 상당히 길었습니다만 도움이 되실거라 믿습니다.

댓글 남기기