16. 람다 함수




1. 람다(lambda) 함수 정의


  • 람다(lambda) 함수 (or 축약 함수): https://wikidocs.net/64
    • 일반적인 함수를 한 줄의 문(Statement)으로 정의할 수 있는 새로운 함수 정의 리터럴
      • 함수 몸체에는 식(expression)만이 올 수 있다.
    • 대부분의 경우 함수 이름을 정의하지 않으면서 일회성으로 활용할 함수를 정의할 때 활용
    • 구문(syntax)
      • lambda 콤마로 구분된 인수들: 식(expression)

1-1 람다 함수 정의 예

  • 인수가 한 개 있는 람다 함수
In [2]:
f = lambda x: x + 1
print(f(1))
2
  • 인수가 두 개 있는 람다 함수를 지니는 변수 지정 및 함수 호출
In [3]:
g = lambda x, y: x + y
print(g(1, 2))
3
  • 기본 인수를 지니는 람다 함수 정의
In [4]:
incr = lambda x, inc = 1: x + inc
print(incr(10))#inc 기본 인수 값으로 1 사용
print(incr(10, 5))
11
15
  • 가변 인수를 지니는 람다 함수 정의
In [7]:
vargs = lambda x, *args: args
print(vargs(1,2,3,4,5))
# 이전 jupyter notebook 참고; "넣어주는 인수 값들 중 일반 인수에 할당되는 값을 제외한 나머지 값들을 지닌 튜플 객체가 할당된다."
print(type(vargs))
print(type(vargs(1,2,3,4,5)))
(2, 3, 4, 5)
<class 'function'>
<class 'tuple'>

1-2 람다 함수 사용하기

In [8]:
def f1(x):
    return x*x + 3*x - 10

def f2(x):
    return x*x*x

def g(func):
    return [func(x) for x in range(-10, 10)]

print(g(f1))
print(g(f2))
[60, 44, 30, 18, 8, 0, -6, -10, -12, -12, -10, -6, 0, 8, 18, 30, 44, 60, 78, 98]
[-1000, -729, -512, -343, -216, -125, -64, -27, -8, -1, 0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
In [9]:
def g(func):
    return [func(x) for x in range(-10, 10)]

print(g(lambda x: x*x + 3*x - 10))
print(g(lambda x: x*x*x))
[60, 44, 30, 18, 8, 0, -6, -10, -12, -12, -10, -6, 0, 8, 18, 30, 44, 60, 78, 98]
[-1000, -729, -512, -343, -216, -125, -64, -27, -8, -1, 0, 1, 8, 27, 64, 125, 216, 343, 512, 729]
  • 람다 함수를 사용하는 코드 예제
In [2]:
# 더하기, 빼기, 곱하기, 나누기에 해당하는 람다 함수 리스트 정의
func_list = [
    lambda x, y: int(x) + int(y), 
    lambda x, y: int(x) - int(y), 
    lambda x, y: int(x) * int(y), 
    lambda x, y: int(x) / int(y)
]

def menu():
    print("0. add")
    print("1. sub")
    print("2. mul")
    print("3. div")
    print("4. quit")
    return int(input('Select menu:'))

while 1:
    sel = menu()                     
    if sel < 0 or sel > len(func):   
        continue
    if sel == len(func):             
        break
    x = int(input('First operand:'))
    y = int(input('Second operand:'))     
    print('Result =', func_list[sel](x,y))
0. add
1. sub
2. mul
3. div
4. quit
Select menu:0
First operand:20
Second operand:30
Result = 50
0. add
1. sub
2. mul
3. div
4. quit
Select menu:2
First operand:10
Second operand:10
Result = 100
0. add
1. sub
2. mul
3. div
4. quit
Select menu:4

2 람다 함수의 활용


  • map, filter, reduce 내장 함수
    • 첫번째 인자: function
      • 첫번째 인자는 일반적으로 람다 함수를 인자로 받는다.
    • 두번째 인자: 시퀀스 자료형 (문자열, 리스트, 튜플)

2-1 map 내장 함수

  • map(function, seq)
    • (python2) seq 시퀀스 자료형이 지닌 각 원소값들에 대해 function에 적용한 결과를 동일 시퀀스 자료형으로 반환한다.
    • (python3) seq 시퀀스 자료형이 지닌 각 원소값들에 대해 function에 적용한 원소를 지닌 map 객체를 반환한다.
      • 이후 동일한 자료형으로 다시 변환 필요
In [14]:
def f(x):
    return x * x

X = [1, 2, 3, 4, 5]
m = map(f, X)
print(type(m))
<class 'map'>
In [3]:
def f(x):
    return x * x

X = [1, 2, 3, 4, 5]
Y = list(map(f, X)) 
#기존: Y = map(f, X)
# X seq 자료형이 리스트라면, list()를 써주어야 한다.
print(Y)
[1, 4, 9, 16, 25]
  • map 내장 함수를 사용하지 않을 때 코드
In [4]:
def f(x):
    return x * x

X = [1, 2, 3, 4, 5]
Y = []
for x in X:
    y = f(x)
    Y.append(y)
print(Y)
[1, 4, 9, 16, 25]
  • map과 람다 함수를 동시에 사용하는 코드 (가장 추천하는 코드)
In [5]:
X = [1, 2, 3, 4, 5]
print(list(map(lambda x: x * x, X)))
[1, 4, 9, 16, 25]
  • range(10)의 모든 값 x에 대해 f = x * x + 4 * x + 5의 계산 결과를 리스트로 구함
In [6]:
Y = list(map(lambda x: x * x + 4 * x + 5, range(10)))
print(Y)
[5, 10, 17, 26, 37, 50, 65, 82, 101, 122]
  • 각 단어들의 길이 리스트
In [7]:
y = list(map(lambda x: len(x), ["Hello", "Python", "Programming"]))
print(y)
[5, 6, 11]

2-2 filter 내장 함수

  • filter(function, seq)
    • (python2) seq 시퀀스 자료형이 지닌 각 원소값들에 대해 function에 적용한 결과가 참인 원소값들만을 동일 시퀀스 자료형으로 반환한다.
    • (python3) seq 시퀀스 자료형이 지닌 각 원소값들에 대해 function에 적용한 결과가 참인 원소값들만을 지닌 filter 객체를 반환한다.
      • 이후 동일한 자료형으로 다시 변환 필요
In [9]:
print(list(filter(lambda x: x > 2, [1, 2, 3, 34])))
[3, 34]
  • 위 코드는 아래와 동일하다.
In [10]:
y = []
for x in [1, 2, 3, 34]:
    if x > 2:
        y.append(x)
print(y)
[3, 34]
  • 주어진 시퀀스 내에 있는 정수중 홀수만 필터링
In [11]:
print(list(filter(lambda x: x % 2, [1, 2, 3, 4, 5, 6])))
[1, 3, 5]
  • 주어진 시퀀스 내에 있는 정수중 짝수만 필터링
In [12]:
print(list(filter(lambda x: x % 2 - 1, [1, 2, 3, 4, 5, 6])))
[2, 4, 6]
  • 특정 범위에 있는 정수만 필터링
In [13]:
def F():
    x = 1
    print(list(filter(lambda a: a > x, range(-5, 5))))
    
F()
[2, 3, 4]

python2 --> python3

(python2)

  • map과 filter의 결과는 주어진 seq 자료형과 동일함
In [15]:
#추가됨
print(filter(lambda x: x > 2, [1, 2, 3, 34]))
print(filter(lambda x: x > 2, (1, 2, 3, 34)))
print(filter(lambda x: x < 'a', 'abcABCdefDEF'))
<filter object at 0x1033b1470>
<filter object at 0x1033b14e0>
<filter object at 0x1033b1470>
In [16]:
#추가됨
print(list(filter(lambda x: x > 2, [1, 2, 3, 34])))
print(tuple(filter(lambda x: x > 2, (1, 2, 3, 34))))
print(str(filter(lambda x: x < 'a', 'abcABCdefDEF')))
[3, 34]
(3, 34)
<filter object at 0x1033b1588>
In [17]:
#기존(python2)
print filter(lambda x: x > 2, [1, 2, 3, 34])
print filter(lambda x: x > 2, (1, 2, 3, 34))
print filter(lambda x: x < 'a', 'abcABCdefDEF')
  File "<ipython-input-17-f2c744c9cb61>", line 2
    print filter(lambda x: x > 2, [1, 2, 3, 34])
               ^
SyntaxError: invalid syntax

2-4 reduce 내장 함수

  • reduce (function, seq[, initial])
    • 파이썬3에서 reduce() 내장 함수 지원하지 않음.
    • 파이썬3에서 reduce() 함수를 사용하려면 다음의 라인을 상단에 추가해주어야 한다.
      • from functools import reduce
    • seq 시퀀스 자료형이 지닌 원소값들에 대해 function 함수를 적용하면서 하나의 값으로 축약한다.(reduce returns a single value.)
    • 첫번째 인자인 function 함수는 반드시 두 개의 인자 (예를 들어, x, y)를 받아야 한다.
      • seq 시퀀스 자료형의 각 원소값들은 각 단계별로 y에 순차적으로 들어간다.
      • 함수가 수행된 값은 각 단계별로 x에 순차적으로 들어간다.
    • 추가적으로 제공가능한 세번째 인자인 initial은 첫번째 단계에 x에 할당할 초기값으로 사용된다.
    • 참고: https://www.python-course.eu/python3_lambda.php
In [34]:
from functools import reduce
In [35]:
print(reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]))
15
단계 x y reduce
1 0 1 1
2 1 2 3
3 3 3 6
4 6 4 10
5 10 5 15
  • initial 값 할당
In [36]:
print(reduce(lambda x, y: x + y, [1, 2, 3, 4, 5], 100))
115
  • 1부터 10까지 각 수에 대한 제곱값을 모두 더한 결과 구함
In [37]:
print(reduce(lambda x, y: x + y * y, range(1, 11), 0))
385
In [38]:
x = 0
for y in range(1, 11):
    x = x + y * y
print(x)
385
  • 문자열 순서 뒤집기
In [39]:
print(reduce(lambda x, y: y + x, 'abcde'))
edcba
단계 x y reduce
1 '' 'a' 'a'
2 'a' 'b' 'ba'
3 'ba' 'c' 'cba'
4 'cba' 'd' 'dcba'
5 'dcba' 'e' 'edcba'

참고 문헌: 파이썬(열혈강의)(개정판 VER.2), 이강성, FreeLec, 2005년 8월 29일