[PythonBasic] Lambda

Alex of the year 2020 & 2021·2020년 9월 7일
0

Python

목록 보기
14/18
post-thumbnail

Lambda

람다 함수를 볼 때면 람바다 노래를 흥얼거리게 된다.
(분명 나만 그런거 아닐거라고 생각한다.)

자 그래서 람다란,

  • 함수를 생성할 때 사용하는 예약어로 def와 동일한 역할. def를 사용해야할 정도로 복잡하지 않거나 def를 사용할 수 없는 곳에 주로 쓰임
  • '함수를 한 줄로 이름 없이, 리턴 없이 간결하게 만들 때'
    --> 조금 어려운 말로 런타임에 생성해서 사용할 수 있는 익명 함수
  • 쓰고 버리는 일회성 함수 (계속 사용하지 않음)
  • filter(), map(), reduce()와 같은 전형적인 기능 개념과 함께 사용되는 강력한 개념
  • 리스트에 넣어 사용이 가능

Basic

아래 코드는 내가 원래 알던 함수 작성법 & 함수 실행 결과

>>> def add(a, b):
	return a+b
    
>>> result = add(3, 4)
>>> print(result)
7

같은 코드를 람다로 적으면 이렇게 아래와 같이 간결하게 적히고
같은 결과 값을 볼 수 있다.

>>> add = lambda a, b: a+b
>>> result = add(3, 4)
>>> print(result)
7

lambda
lambda 매개변수1, 매개변수2, ... : 매개변수를 사용한 표현식


Lambda with List

람다 함수의 특징 중에는
리스트로 넣어 사용이 가능하다는 점이 있다.

다음의 코드를 보자.

>>> lambdas = [lambda x:x+10, lambda x:x+100]

>>> print(lambdas[0](5)) 
>>> 15

>>> print(lambdas[1](5))
>>> 105

람다 함수를 리스트의 요소값처럼 사용하였다.


Lambda with Dictionary (sorted())

람다 함수를 이용하면 딕셔너리를 정렬할 수도 있다.
다음의 코드들을 보자.

먼저, 아래의 코드는 람다를 사용하지 않을 때의 가장 기본적인 딕셔너리 정렬 방법이다.

fruit = {'apple':5, 'grape':10, 'banana':7, 'peach':3, 'melon':2}

def f1(x):
	return x[0]

sorted1 = sorted(fruit.items(), key=f1)
# key, value 함께 출력하려면 .items() 사용 잊지 않기

print(sorted1)

>>> [('apple', 5), ('banana', 7), ('grape', 10), ('melon', 2), ('peach', 3)]
# key를 기준으로 abc 순서에 맞추어 정렬되었다.
# 왜냐하면, f1(x)함수 정의 시, return 값을 x[0]으로 설정해두었고,
# x[0]이란 결국 딕셔너리 요소 값의 key 값을 의미하기 때문이다.

# 만일, key값이 아니라 value값을 기준으로 정렬하고자한다면
# f1(x) 함수 정의 시, return 값을 x[1]로 설정하면
# [('melon', 2), ('peach', 3), ('apple', 5), ('banana', 7), ('grape', 10) ] 의 결과값을 볼 수 있을 것이다.

하지만 람다함수를 사용할 경우, 따로 함수를 만들지 않더라도 정렬이 가능하다.

fruit = {'apple':5, 'grape':10, 'banana':7, 'peach':3, 'melon':2}

sorted1 = sorted(fruit.items(), key=lambda x:x[0])
>>> [('apple', 5), ('banana', 7), ('grape', 10), ('melon', 2), ('peach', 3)]
# key를 기준으로 정렬

sorted2 = sorted(fruit.items(), key=lambda x:x[1])
>>> [('melon', 2), ('peach', 3), ('apple', 5), ('banana', 7), ('grape', 10) ]
# value를 기준으로 정렬

위처럼 람다 함수로 딕셔너리 정렬도 간단하게 한 줄로 할 수 있다.

sorted()

1)

myDict = {3:1,2:3,1:4}
sorted(myDict.items(), key=lambda x:x[1])

>>>[(3, 1), (2, 3), (1, 4)] (value값 중심으로 정렬)

2)

myList = ["hello", "python", "hi"]
sorted(myList, key=lambda x:x[1])

>>> ["hello", "hi", "python"]
출력 값: 문자열 요소 중 2번째 문자를 기준으로 정렬(각각 e, i, y)

Lambda with list(), map(), filter()

map()

map()은 두 개의 인수를 가지는 함수이다.
r = map(funcion, iterable)
첫번째 인자인 function은 함수의 이름에 해당하며 iterable은 대표적으로 list, str, tuple등을 들 수 있겠다.
map()함수는 functiondp의해 변경된 iterator를 반환한다.

>>> a = [1, 2, 3, 4]
>>> b = [17, 12, 11, 10]
>>> list(map(lambda x, y: x+y, a, b))
[18, 14, 14, 14]

filter()

filter() 역시 두 개의 인수를 가지는 함수이다.
r = filter(function, iterable)
filter에 인자로 사용되는 function은 처리되는 각각의 요소에 대해 Boolean 값을 반환한다. True 반환 시 해당 요소는 남게되고 False 반환 시 해당 요소는 걸러져 제거된다.

>>> foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
>>> list(filter(lambda x: x%3==0, foo))
[18, 9, 24, 12, 27]

reduce()

reduce()는 역시 두 개의 필수 인자와 하나의 옵션 인자를 가진다.
reduce()함수는 내장 함수가 아니므로 functools에서 reduce를 임포트하여 사용한다.
functools.reduce(function, iterable[, initializer])
아래 식을 보는 것이 빠르다.
약간 요소 하나하나를 먹어치우면서 줄여가는 느낌으로 실행한다.

>>> from functools import reduce
>>> reduce(lambda x, y: x+y, [1, 2, 3, 4, 5])
15

# 1+2, 3, 4, 5
# 1+2+3, 4, 5
# 1+2+3+4, 5
# 1+2+3+4+5

Lambda의 확장성과 독립성

다음의 코드는 inc 함수로 lambda 함수를 즉석에서 생성하고 반환하는 함수를 정의한다. 작성된 함수들(f, g)은 인수 작성 시, 지정된 값만큼을 증가시켜 리턴한다.

>>> def inc(n):
		return lambda x: x+n
        
>>> f = inc(2)
>>> g = inc(4)

>>> print(f(12))
14

# 위의 함수는 아래처럼 써도 그 리턴값이 같다
>>> print(inc(2)(12))
14

>>> print(g(12))
16

람다 자체도 함수인데 이런 람다를 품은 함수를 만들어보았다.
람다의 이 특성을 잘 활용하면 함수의 확장성이 상당히 좋을 것으로 예상된다.


Lambda 활용 문제

Question.

다음과 같이 비밀번호의 길이와 대문자가 포함된 것을 확인하는 간단한 함수가 있다.

def check_password(password):
    if len(password) < 8:
        return 'SHORT_PASSWORD'

    if not any(c.isupper() for c in password):
        return 'NO_CAPITAL_LETTER_PASSWORD'

    return True

이 함수에 있는 if문 두 개를 람다표현식을 이용하여 다음과 같은 형식으로 작성해보자.

lambdas = [ 

]

def check_password_using_lambda(password):

    for f in lambdas:
        if f(password) is not None:
            return f(password)

    return True

참고로 람다 표현식을 사용한 결과는 다음과 같아야 한다.

>> print( check_password_using_lambda('123') )            
SHORT_PASSWORD

>> print( check_password_using_lambda('12356789f') )      
NO_CAPITAL_LETTER_PASSWORD

>> print( check_password_using_lambda('123456789fF') )    
True

Answer.

import types

Lambdas = [
    lambda x : 'SHORT_PASSWORD' if len(x)<8 else None,
    # lambda는 return을 쓰지 않으므로 return 값에 해당하는 값을 
    # 맨 앞에 문자열로 두고, 뒤에 조건을 쓴다. else None 이후 , 찍는 것도 잊지 말자
    lambda x : 'NO_CAPITAL_LETTER_PASSWORD' if not any(i.isupper() for i in x) else None
    # 여기서 헷갈렸던 것이 True 부분 리턴도 여기에 적어야 하나 하는 것이었다.
    # 그 부분은 아래 실제 함수에 적어두자. 
]

def check_password_using_lambda(x):

    for f in Lambdas:
        if f(x) is not None:
            return f(x)

    return True

결과 출력 시,

>>> print( check_password_using_lambda('123') )            
SHORT_PASSWORD

>>> print( check_password_using_lambda('12356789f') )      
NO_CAPITAL_LETTER_PASSWORD

>>> print( check_password_using_lambda('123456789fF') )    
True



+) AWS Lambda라는 것도 있다는데, 다음번에는 그 부분도 공부해보자.




references:
https://www.youtube.com/watch?v=3zOypvH42jY (프로그래머 김플 스튜디오 람다1)
https://www.youtube.com/watch?v=h4HYbLs0LhM (프로그래머 김플 스튜디오 람다2)
https://blog.naver.com/timtaeil/221426580068 (sorted())
https://offbyone.tistory.com/73 (람다)

profile
Backend 개발 학습 아카이빙 블로그입니다. (현재는 작성하지 않습니다.)

0개의 댓글