[파이썬 입문] 4. 함수 – 3) 람다와 콜백 등

람다

람다는 간단한 알고리즘 코드 블록입니다.

lambda 입력인자목록: 수행코드

함수는 알고리즘 코드 블록에 이름(함수명)을 명명하여 호출하여 사용할 수 있게 만든 재사용성 높은 코드입니다.

반면 람다는 이름을 명명하지 않은 알고리즘 코드로 간단하게 알고리즘을 표현할 수 있다는 장점을 갖습니다.

다음은 입력 인자로 전달받은 값에 1을 더한 값을 반환하는 함수를 정의하고 호출한 코드입니다.

[In]
def add_one(x):
  return x+1
print(add_one(1))
[out]
2

이를 람다로 표현한다면 다음처럼 표현할 수 있어요.

[In]
fun = lambda x: x+1
print(print(fun(1))
[out]
2

콜백

콜백은 호출 방향이 반대 방향이라는 의미입니다.

사용자 정의 코드에서 함수를 호출하는 것이 정상적인 호출방향입니다.

반대로 함수에서 사용자 정의 코드를 호출한다면 호출 방향이 반대 방향이라고 할 수 있으며 콜백입니다.

콜백은 함수 호출 시에 알고리즘(함수 혹은 람다)을 입력 인자로 전달하고 호출받은 함수에서는 전달받은 알고리즘을 호출하여 사용하는 것입니다.

다음은 콜백을 설명하기 위해 알고리즘으로 전달할 함수(콜백 용도로 전달할 함수)입니다.

[In]
def cb_fun(msg,ls):
  print(msg)
  for e in ls:
    print("this is callback:",e)

다음은 입력인자로 알고리즘을 전달받아 함수 내부에서 이를 호출(콜백 호출)하는 함수입니다.

[In]
def print_sort_ba(ls,cb):
  cb("before",ls)
  ls.sort()
  cb("after",ls)

이제 print_sort_be 함수를 호출할 때 두 번째 인자로 알고리즘(여기서는 cb_fun함수)을 전달합니다.

[In]
print_sort_ba([1,3,5,2,6,7,3],cb_fun)
[out]
before
this is callback: 1
this is callback: 3
this is callback: 5
this is callback: 2
this is callback: 6
this is callback: 7
this is callback: 3
after
this is callback: 1
this is callback: 2
this is callback: 3
this is callback: 3
this is callback: 5
this is callback: 6
this is callback: 7

수행 결과를 보면 print_sort_be 함수에서는 전달받은 cb_fun 함수를 호출하여 정렬 전과 정렬 후의 리스트 내용을 출력하는 것을 확인할 수 있어요.

이번에는 내장 함수 sorted의 key 파라미터에 람다 식으로 알고리즘을 전달해 볼게요.

sorted 함수에 회원(이름과 번호) 목록과 key에 람다 식(회원[0]: 이름)을 전달하여 이름 순으로 정렬하고 있습니다.

sorted 함수 내부에서는 전달받은 람다 식을 이용하여 정렬에 사용합니다.

[In]
members = [["홍길동",3],["강감찬",5],["을지문덕",4],["고길동",7]]
s_members = sorted(members,key=lambda m:m[0])
print(s_members)
[out]
[['강감찬', 5], ['고길동', 7], ['을지문덕', 4], ['홍길동', 3]]

콜백 함수를 사용하는 내장 함수 중에 filter와 map은 자주 사용합니다.

filter는 컬렉션에 특정 알고리즘을 적용하였을 때 참인 요소를 필터링하는 개체를 생성하는 함수입니다.

filter(알고리즘, 컬렉션)

map은 컬렉션의 모든 요소에 특정 알고리즘을 적용하는 개체를 생성하는 함수입니다.

map(알고리즘, 컬렉션)

filter와 map을 이해하기 위해 0에서 19(20-1) 범위의 요소로 리스트를 생성할게요.

[In]
ls = list(range(20))
print(ls)
[out]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

filter에 2로 나누어 몫이 0일 때 참인 알고리즘과 위의 리스트를 입력인자로 전달할게요.

filter함수에서는 리스트의 각 요소 중에 전달한 알고리즘(2의 배수를 판별)이 참인 요소만 추출하는 개체를 반환합니다.

이를 list 함수의 입력 인자로 전달하면 0~19(20-1)범위에서 2의 배수인 요소인 리스트를 생성합니다.

[In]
even_filter = filter(lambda x:x%2==0,ls)
e_ls = list(even_filter)
print(e_ls)
[out]
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]

이번에는 입력 인자의 제곱을 계산하는 알고리즘을 람다 식으로 정의하여 map 함수에 위의 리스트와 함께 전달하게요.

map은 컬렉션의 모든 요소에 해당 알고리즘을 수행하는 개체를 반환합니다.

이를 list 함수에 전달하면 0에서 19(20-1)범위의 값의 제곱으로 요소를 구성한 리스트를 생성합니다.

[In]
sq_map = map(lambda x:x**2, ls)
sq_ls = list(sq_map)
print(sq_ls)
[out]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144, 169, 196, 225, 256, 289, 324, 361]

튜플과 함수 리턴

파이썬 개발자들은 함수에서 여러 개의 값을 반환할 수 있다고 생각합니다.

실제는 튜플을 반환하는 것인데 여러 개의 값을 반환한다고 생각하더라도 문제가 없습니다.

앞에서 튜플을 소개할 때 소괄호에 열거하거나 혹은 괄호 없이 열거한 것을 변수에 대입하면 내부적으로 튜플 형식이라는 것을 얘기했어요.

[In]
a = 2,3
print(type(a))
print(a)
[out]
<class 'tuple'>
(2, 3)

함수를 정의할 때 두 개 이상의 값을 반환할 필요가 있을 때 단순히 반환할 값을 return 뒤에 열거합니다.

내부적으로 튜플 형태로 반환하겠죠.

다음은 컬렉션의 요소 합계와 평균을 반환하는 함수입니다.

[In]
def get_sum_average(ls):
  s = 0
  for e in ls:
    s += e
  return s, s/len(ls)

사용하는 곳에서 반환한 값을 사용할 수 있겠죠.

[In]
ls = [1,6,3,7,9,5]
re = get_sum_average(ls)
print(re)
[out]
(31, 5.166666666666667)

대입 연산에서 튜플(혹은 리스트)의 요소 개수만큼 변수를 선언하여 사용할 수 있습니다.

[In]
s,aver = get_sum_average(ls)
print(f"합계:{s} 평균:{aver:.2f}")
[out]
합계:31 평균:5.17

이러한 특징 때문에 파이썬의 함수는 여러 개의 값을 반환할 수 있다고 하는 것입니다.