코린이의 소소한 공부노트

람다(Lambda)함수 이해 및 사용하기 본문

Python

람다(Lambda)함수 이해 및 사용하기

무지맘 2021. 6. 11. 18:17

함수를 정의해서 사용하다 보면 한 번씩 드는 생각이 있다.

몇 번 안쓰는 함수인데, 매번 식을 써서 쓰기는 귀찮은데 함수 정의를 하자니 너무 거창한 거 같다는 생각.. (나만 그런가?)

예를 들면 두 수를 더한 수에 2를 곱하는 식을 쓴다고 하면 아래와 같이 쓸 수 있다.

# 1. 함수 없이 쓰기
a = (3+4)*2
print(a)
>> 14

# 2. 재사용을 위해 함수 정의
def addmul(x,y):
    return (x+y)*2

b = addmul(3,4)
print(b)
>> 14

함수를 def 키워드를 이용해서 정의를 하면 함수 객체가 생성되고, 메모리 어느 한쪽 구석에서 자리 차지를 하고 있다. 그리고 프로그램 어딘가에서 함수를 호출하면 자리 차지를 하고 있던 함수를 불러와서 쓴다. 메모리가 낭비된다는 생각이 들어 del 키워드로 변수가 참조된 것을 지우면 메모리 낭비가 되던 것을 막을 수는 있지만, del을 쓰는 것 또한 시간 낭비이다. (이렇게 세상 단호하게 말하다니.. 누가 보면 초 단위로 스케줄 관리하는줄..)

이번에 볼 것은 함수를 보다 간결하게 쓸 수 있는

1. 람다함수와

2. 람다함수가 유용하게 사용되는 함수들이다.


1. 람다(Lambda)함수


람다함수란

1) 단일문으로 표현되는 익명(이름이 없는)함수이다.

2) 입력(인자 리스트)과 출력(표현식)으로 이루어져 있는 함수이다.

3) 굳이 def를 이용해 정의하지 않고, 1회성으로 쓰고 싶을 때 사용하는 함수이다.

맨 위에서 봤던 예시를 다시 써보겠다.

# 1. 함수 없이 쓰기
a = (3+4)*2
print(a)
>> 14

# 2. 재사용을 위해 함수 정의
def addmul(x,y):
    return (x+y)*2

b = addmul(3,4)
print(b)
>> 14

# 3. 람다 키워드를 이용해보기
(lambda x,y:(x+y)*2)(3,4)
>> 14

# 4. 람다함수를 정의하면서 변수에 선언하기
func1 = lambda x,y:(x+y)*2
print(func1(3,4))
>> 14

위에서 봤듯이 람다함수 이용 방법은 lambda 입력:출력이다.

입력에는 함수 정의 시 필요한 인자들을 받으면 된다. 여러 개를 써도 상관없다.

출력에는 리턴해주고 싶은 계산식(표현식)을 쓰면 된다. 뭐든 상관없다.

# 10보다 크면 '우와'
# 10보다 작으면 '오잉'

# 1. 함수 정의
def if_func1(x):
    if x>10:
        return '우와'
    else:
        return '오잉'

# 2. 람다 키워드 이용
if_func2 = lambda x:'우와'if x>10 else '오잉'

람다함수도 객체이긴 하지만, def를 이용해서 만든 함수보다 많은 이점이 있다.

1) 함수 이름을 정하는 시간을 줄여준다. - 함수를 정의할 때 생각보다 많은 시간을 함수이름, 변수이름 등에 쓰고 있다!

2) 코드가 간결해져 가독성을 높여준다. - A개발자가 def로 함수를 정의해둔 함수를 B개발자가 쓸 때, 함수의 기능이 정확히 무엇인지 알려면 코드를 찾아봐야 한다. 하지만 람다함수로 쓰면 이 코드를 작성한 개발자가 아니어도 기능을 바로 알 수 있다.

3) 메모리를 절약할 수 있다. - 람다 키워드가 있는 코드를 실행하고 다음 코드로 넘어가면 람다함수가 있던 객체가 메모리에서 바로 제거가 된다.

 

물론 단점도 있다.

1) 함수의 코드가 너무 길면 오히려 가독성이 떨어진다. - 이 경우에는 그냥 def로 정의하는 게 낫다.

2) 오류가 생겼을 때 이름이 없기 때문에 어디서 오류가 발생했는지 찾기 힘들다(디버깅을 하는게 힘들다).

def func1(x,y):
    return x/y
print(func1(3,0))
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-13-0bc83935b9d7> in <module>
      1 def func1(x,y):
      2     return x/y
----> 3 print(func1(3,0))

<ipython-input-13-0bc83935b9d7> in func1(x, y)
      1 def func1(x,y):
----> 2     return x/y
      3 print(func1(3,0))

ZeroDivisionError: division by zero

 

이 func1 함수를 람다로 쓰면 이런 에러 메시지가 뜬다.

print((lambda x,y:x/y)(3,0))
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-19-7c05a5cea290> in <module>
----> 1 print((lambda x,y:x/y)(3,0))

<ipython-input-19-7c05a5cea290> in <lambda>(x, y) # 여기
----> 1 print((lambda x,y:x/y)(3,0))

ZeroDivisionError: division by zero

def로 함수 정의를 했을 때는 오류가 뜬 함수의 이름이 바로 나오지만 주석(#여기)이 달린 부분처럼 람다에서 잘못됐다고만 나온다. 코드가 매우 긴 프로그램에 비슷하게 생긴 람다함수가 여러 개 일 경우 함수 이름이 없기 때문에 오류 추적이 쉽지 않다.

 

람다를 센스 있게 활용하면 코딩이 훨씬 더 간결해지고 시간도 절약되고 가독성도 높아지는 이점을 챙길 수 있다. 람다함수가 어떤 함수와 합이 잘 맞는지 살펴보겠다.


2. 람다함수가 유용하게 사용되는 함수들


 

지금부터 볼 함수들은 자기 역할을 할 때 다른 기능이 필요하다. 필요한 기능을 만들어서 사용하긴 해야 하는데 이 함수에서만 쓸 것이기 때문에 해당 기능을 def로 함수를 정의하는 것이 사치(?)라고 느껴질 때 람다를 이용한다.

 

1) filter함수 - filter(함수, 리스트): 특정 조건을 만족하는 요소만 남기고 나머지는 필터링한다(삭제한다).

# 홀수만 남기고 싶다.
numbers = [9, 1, 32, 52, 94, 68, 13, 4, 47]

# 1. def로 정의
def odd(m):
    return m%2 == 1
print(list(filter(odd, numbers)))
>> [9, 1, 13, 47]

# 2. lambda로 정의
print(list(filter(lambda x:x%2==1, numbers)))
>> [9, 1, 13, 47]

- filter의 입력으로 들어가는 리스트는 변하지 않는다.

- filter함수의 결과는 filter객체이기 때문에 list로 변환해서 결과를 출력해봐야 내용물을 확인해볼 수 있다.

2) map함수 - map(함수, 리스트): 각 원소들을 주어진 수식에 따라 계산(변형)하여 새로운 리스트를 반환해준다.

# 모든 원소에 10을 더한 리스트를 만들고 싶다.
numbers = [1, 2, 3, 4, 5, 6]

# 1. def로 정의
def add(m):
    return m+10
print(list(map(add, numbers)))
>> [11, 12, 13, 14, 15, 16]

# 2. lambda로 정의
print(list(map(lambda x:x+10, numbers)))
>> [11, 12, 13, 14, 15, 16]

- map함수의 입력으로 들어가는 리스트는 변하지 않는다.

- map함수의 결과는 map객체이기 때문에 list로 변환해서 결과를 출력해봐야 내용물을 확인해볼 수 있다.

- 리스트를 여러 개 쓸 수 있다.

# 앞에서 순서대로 두 원소씩 더한 값 리스트를 만들고 싶다.
a = [1, 2, 3]
b = [4, 5, 6]
print(list(map(lambda x,y:x+y, a, b)))
>> [5, 7, 9]

3) reduce함수: 1, 2번째 원소를 가지고 연산한 후, 그 결과와 3번째 원소를 연산한다. 그리고 그 결과로 다음 원소와 또 연산을 한다. 이렇게 이전 연산의 결과와 다음 원소를 짝지어 연쇄적으로 계산하고 마지막 출력 1개만 반환해준다.

reduce를 쓰려면 functools라는 모듈을 임포트한 후 써야 한다.

# 리스트 내의 모든 숫자의 합이 궁금하다.
nums = [1, 2, 3, 4, 5]

# 1. for문
result = 0
for n in nums:
    result += n
print(result)
>> 15

# 2. lambda 이용
import functools as ft
print(ft.reduce(lambda x,y:x+y, nums))
>> 15

4) if 조건문: 함수는 아니지만, 간단한 논리라면 람다가 유용하게 쓰인다. 위에서 봤던 if문 예시를 다시 갖고 와서 보면,

# 10보다 크면 '우와'
# 10보다 작으면 '오잉'

# 1. 함수 정의
def if_func1(x):
    if x>10:
        return '우와'
    else:
        return '오잉'

# 2. 람다 키워드 이용
if_func2 = lambda x:'우와'if x>10 else '오잉'

if문을 람다함수에 쓸 때는 lambda 입력: 결과1 if 조건 else 결과2형태이다. 여기서

- 결과1은 if 조건이 참일 때, 결과2는 거짓일 때의 출력 값이다.

- elif는 쓸 수 없다.

- 콜론 :을 쓰지 않는다.

- if 여러 번 사용은 가능하다.


<요약>

 

1. 람다(lambda)함수: lambda 입력:출력

- 익명함수

- 코드 간결, 잘 쓰면 가독성 좋음, 메모리 절약

- 오류 추적 불편, 잘못 쓰면 복잡함

2. 람다함수가 유용하게 쓰이는 함수

- filter: 조건이 참인 것만 남겨둠

- map: 원소 하나마다 동일한 연산을 함

- reduce: 두 개씩 짝지어 함수로 계산 후 결과 1개 반환

'Python' 카테고리의 다른 글

클래스, 오브젝트  (0) 2021.06.25
모듈의 이해 및 사용 - import  (0) 2021.06.18
함수를 이해하고 활용해보기  (0) 2021.05.27
공부하면서 만난 연습문제들 - 파이썬편  (0) 2021.05.21
반복문 - while, for  (0) 2021.05.21