TIL

TIL. 28 람다 표현식(lambda) 사용하기

codermun 2020. 11. 5. 18:23
728x90
반응형

## lambda 표현식

## 람다 표현식은 식 형태로 되어 있어 람다 표현식이라 부르며,

## 함수를 간편하게 작성할 수 있어, "다른 함수의 인수"로 넣을때 자주 사용한다.


## 반화 값으로 매개변수 x + 10 형태의 함수를 람다 표현식으로 함수를 해보자

1. def 

def ppp(x):
    return x+10

print(ppp(1))
::
11

2. 람다 표현식

# 람다 표현식은 다음과 같이 lambda에 매개변수를 지정하고 :(콜론) 뒤에 반환값으로 사용할 식을 지정한다.

# lambda 매개변수들: 식

lambda x : x+10

# 람다 표현식을 위와 같이 작성하면 함수 객체가 생성되는데, 이 상태만으로는 함수를 호출 할 수 없다.

# 람다 표현식은 "이름없는"함수를 만들기 때문이다, 이때문에 람다 표현식을 익명 함수(anonymous function) 라고도 부른다.

## 람다로 만든 함수를 호출하기 위해선 임의의 변수에 할당하여 호출하면 된다.

a = lambda x : x+10

print(a(10))
::
20

## 람다 표현식을 살펴보면 lambda x: x + 10은 매개변수 x 하나를 받고, x에 10을 더해서 반환한다는 뜻이다.

# 즉, 매개변수, 연산자, 값 등을 조합한 식으로 반환값을 만드는 방식이다

# 다음그림과 같이 def로 만든 함수와 비교해보자.


## 람다 표현식 자체로 호출하기

## 임의의 변수를 할당하지않고 ()로 묶어 람다 표현식 자체만으로도 함수를 호출 할 수 있는 방법이있다.

## (lambda 매개변수들: 식)(인수들) IDLE에서 좀 더 쉽게 확인가능

(lambda x : x+10)(25) # (lambda 매개변수들: 식)(인수들)

print((lambda x : x+10)(25))
::
35

## 람다 표현식안에서는 변수를 만들 수 없다.

(lambda x: y=10; x + y) # error

## 이처럼 y라는 변수를 람다 표현식에 만들 수 없다

## 따라서 반환값 부분은 변수 없이 식 1줄로 작성되어야 하며, 추가 변수가 필요할 경우 def 이용해야한다.


## 람다 표현식은 바깥에 있는 함수를 사용할 수 있다.

y = 20

(lambda x: x+y)(1)

출력시
::
21

 

## 위와 같이 매개변수 x 와 바깥의 변수 y 를 이용해 값을 반환 할 수 있다.


## 람다 표현식을 사용하는 이유

## 람다 표현식은 "함수의 인수 부분에서 함수를 간단하게 만들기 위해 사용한다" 대표적으로 map이다.

 

def plus_ten(x):
    return x + 10

b = list(map(plus_ten, [1, 2, 3])) ## map 객체로 저장되는 값을 사람이 보기 위해 list로 변환시켜주는 과정

print(b)
::
[11, 12, 13]

 

## map은 여러 개의 데이터를 한 번에 다른 형태로 변환하기 위해서 사용한다.

# 따라서, 여러 개의 데이터를 담고 있는 list나 tuple을 대상으로 주로 사용하는 함수이다.

### 지금까지 map을 사용할 때 map(str, [1, 2, 3])와 같이 자료형 int, float, str 등을 넣었다

### 사실 plus_ten처럼 함수를 직접 만들어서 넣어도 된다.

c = list(map(lambda x : x+10 ,[1, 2, 3])) 
# 위 식의 b와 비교해보면 plus_ten 이라는 함수 자리를 람다 표현식으로 대체한 것

print(c)
::
[11, 12, 13]

 

## 위 식의 b와 비교해보면 plus_ten 이라는 함수 자리를 람다 표현식으로 대체한 것이며

## 대체할 경우 def 과정이 사라진 코드 단축효과를 볼 수 있다.

## 이처럼 "함수를 다른 함수의 인수로 넣을때" 편리하다


## 람다 표현식으로 매개변수가 없는 함수 만들기

f = (lambda: 1)()
print(f)
::
1

x = 10
g = (lambda : x)()
print(g)
::
10

## 람다 표현식으로 매개변수가 없는 함수를 만들 때는 lambda 뒤에 아무것도 지정하지 않고 :(콜론)을 붙혀준다.

## 단, 콜론 뒤에는 반드시 반환할 값이 있어야 한다. 왜냐하면 표현식(expression)은 반드시 값으로 평가되어야 하기 때문이다.

## 람다 표현식에서 map, filter, reduce 사용하기

## 람다 표현식에서 조건문 사용하기

# lambda 매개변수들: 식1 if 조건식 else 식2

## map을 이용해 a라는 리스트에서 3의 배수를 문자열로 출력

<IDLE> # not vscode
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

list(map(lambda x : str(x) if x % 3 == 0 else x,a))
:: 
[1, 2, '3', 4, 5, '6', 7, 8, '9', 10]

# map은 리스트의 요소를 각각 처리하므로 lambda 의 반환값도 요소여야 한다.

## 식 1 == str(x) , 조건식 == x % 3 == , 식2 == x


## 람다 표현식에서 조건문 사용시 주의할 점

## 1. if else 조건문 사용시 :(콜론)을 붙히지 않음 (일반적 조건문 문법과 다름)

## 2. 식1 if 조건식 else 식2 // 조건문이 참이면 식1, 거짓일때는 식2를 사용한다.

## 3. if를 사용했다면 반드시 else도 사용해줘야한다. (if만 사용시 error)

## 4. elif 를 사용 할 수 없다


## 람다 표현식에 조건문 여러개 사용하기

# lambda 매개변수들: 식1 if 조건식1 else 식2 if 조건식2 else 식3

# 리스트에서 1은 문자열로 변환하고, 2는 실수로 변환, 3 이상은 10을 더하는 식은 다음과 같이 작성

<IDLE>
list(map(lambda x : str(x) if x== 1 else float(x) if x==2 else x+10,a))
::
['1', 2.0, 13, 14, 15, 16, 17, 18, 19, 20]

 

## lambda 매개변수들: 식1 if 조건식1 else // 식2 if 조건식2 else 식3 ==>

//를 기준으로 왼쪽 조건식 1개, 오른쪽 조건식 1개로 이해하면 편하다

## 위 식을 def로 바꿔 작성해보자

def f(x):
    if x == 1:
        return str(x)
    elif x == 2:
        return float(x)
    else:
        return x+10

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = list(map(f,a))

print(b)
::
['1', 2.0, 13, 14, 15, 16, 17, 18, 19, 20]

## 조건이 복잡하여 이해하거나 알아보기 힘들경우 억지로 람다 표현식을 사용하지 말고, def로 사용하는것을 권장한다.

## 복잡하고 어려운 코드는 작성 후 시간이 지나면 알아보기 어려운 경우가 많으니,

코드는 길이가 조금 길어지더라도 알아보기 쉬워야 한다.(중요)


## mpa에 객채 여러개 넣기

<IDLE>
a = [1, 2, 3, 4, 5]
b = [2, 4, 6, 8, 10]

list(map(lambda x, y: x * y, a, b))
::
[2, 8, 18, 32, 50]

## map은 리스트 등의 반복 가능한 객체를 여러개 넣을 수 있다.

## 위 코드는 두 리스트의 요소를 서로 곱해 새로운 리스트를 만드는 방법이다.

## 리스트 2개를 처리해야하는 경우 lambda x, y : x*y 처럼 매개변수를 2개 지정해주면 된다.

## 그다음 리스트 2개를 ,(콤마)로 구분해 넣어주면 된다.

## 즉, 람다 표현식의 매개변수 개수에 맞춰 반복 가능한 객체를 콤마로 구분하여 넣어주면 된다.

## 여기서 반복 가능한 객체는 a, b 이며, a, b 의 요소의 개수가 다를 경우 요소의 개수가 더 작은 객체를 기준으로 출력해준다

## ex : a = [1, 2] ==> 해당 식의 반환 값은 [2, 8] 까지만 반환

## ex : a = [1, 2, 3, 4, 5, 6, 7, 8] ==> 해당 식의 반환 값은 [2, 4, 6, 8, 10] 까지만 반환 (b의 요소 개수 5개)

 


## filter 사용하기

# filter는 반복 가능한 객체에서 특정 조건에 맞는 요소만 가져오는데,

# filter에 지정한 함수의 반환값이 True일 때만 해당 요소를 가져온다.

# filter(함수, 반복가능한객체)

## def를 이용한 리스트에서 5보다 크면서 10보다 작은 숫자를 가져오기.

a = [8, 3, 2, 10, 15, 7, 1, 9, 0, 11]

def aaa(x):
    return x > 5 and x <10

print(list(filter(aaa, a)))
::
[8, 7, 9]

## 람다 표현식을 이용한 리스트에서 5보다 크면서 10보다 작은 숫자를 가져오기.

a = [8, 3, 2, 10, 15, 7, 1, 9, 0, 11]

b = list(filter(lambda x : x > 5 and x < 10, a))

print(b)
::
[8, 7, 9]

## 즉 filter 는 x > 5 and x <10 조건 중 참인 것만을 가져오고, 거짓은 버림


## reduce 사용하기

# reduce는 반복 가능한 객체의 각 요소를 지정된 함수로 처리한 뒤 이전 결과와 누적해서 반환하는 함수

# (reduce는 파이썬 3부터 내장 함수가 아닙니다. 따라서 functools 모듈에서 reduce 함수를 가져와야 한다)

# from functools import reduce

# reduce(함수, 반복가능한객체)

## def로 reduce 사용하기

from functools import reduce

a = [1, 2, 3, 4, 5]

def bbb (x, y):
    return x+y

print(reduce(bbb, a))
::
15

## 함수 bbb에서 x + y를 반환하도록 만들었으므로 reduce는 그림과 같이 요소 두 개를 계속 더하면서 결과를 누적한다

## 람다 표현식으로 reduce 사용하기

a = [1, 2, 3, 4, 5]

from functools import reduce

c = reduce(lambda x, y : x+y, a)

print(c)
::
15

 


# 참고 | map, filter, reduce와 리스트 표현식

## 리스트(딕셔너리, 세트) 표현식으로 처리할 수 있는 경우에는 map, filter와 람다 표현식 대신 리스트 표현식을 사용하는 것이 좋습니다. list(filter(lambda x: x > 5 and x < 10, a))는 다음과 같이 리스트 표현식으로도 만들 수 있습니다.

<IDLE>
a = [8, 3, 2, 10, 15, 7, 1, 9, 0, 11]

[i for i in a if i > 5 and i < 10]
::
[8, 7, 9]

### 리스트 표현식이 좀 더 알아보기 쉽고 속도도 더 빠릅니다.

 

## 또한, for, while 반복문으로 처리할 수 있는 경우에도 reduce 대신 for, while을 사용하는 것이 좋다.

왜냐하면 reduce는 코드가 조금만 복잡해져도 의미하는 바를 한 눈에 알아보기가 힘들다.

이러한 이유로 파이썬 3부터는 reduce가 내장 함수에서 제외되었다.

 

# reduce(lambda x, y: x + y, a)는 다음과 같이 for 반복문으로 표현할 수 있습니다.

<IDLE>
a = [1, 2, 3, 4, 5]

x = a[0]

for i in range(len(a) - 1):

... x = x + a[i + 1]

...

x
::
15

728x90
반응형