TIL-Python

치삼이·2021년 10월 24일
0
post-thumbnail

Lambda 정리

lambda는 람다 표현식 혹은 익명함수 라고도 불리며 한 번 사용하고 사용되지 않는 함수객체다. lambda는 기존 def 키워드를 이용해 함수를 사용하는 것 보다 아래 두 가지 장점을 갖는다.

  1. 가독성

    람다는 함수를 간편하게 작성할 수 있어서 보기에 편하다(모르겠다).

  2. 메모리 절약

    람다는 Heap에 메모리를 저장하고 한번사용하면 메모리에서 사라진다.

1. Lambda의 기본 문법

람다의 기본 문법은 다음과 같다.

lambda [매개변수] : []

TIL_lambda = lambda x: x**2

print(TIL_lambda(2))
4

위와 같이 lambda는 lambda 명시적으로 선언 한 뒤, 매개변수 을 콜론(:) 으로 구분해서 넣어주면 된다. 다만 lambda 식 내부에서는 변수를 선언 할 수 없다.

또 lambda 역시 익명 함수이기 때문에 자체적으로 함수를 호출할 수없고 위와같이 변수에 할당한뒤 호출해 주어야 한다.

익명 함수이기 때문에 여러가지 인자를 집어 넣을 수 있고 각 인자는 함수와 마찬가지로 쉼표(,) 로 구분한다. 마찬가지로 람다 역시 default argument 혹은 가변 인수 등이 들어갈 수 있으니 인자의 순서에 맞게 넣어야 한다.

test_lambda = lambda x, y, z: x + y + z

test_lambda = lambda x, y=2, *args: print(x, y, args)

2. Lambda와 map, filter, reduce

람다가 가장 빛이날 때는 reduce() map() filter() 같은 함수를 인자로 받는 함수들을 사용할 때 이다.

2.1 map()

파이썬 공식 문서에서 map() 을 찾아보면 다음과 같은 설명이 나온다.

  • map(function, iterable, ...)

    iterable 의 모든 항목에 function 을 적용한 후 그 결과를 돌려주는 이터레이터를 돌려줍니다.

list 같은 이터레이터를 와 함수를 집어 넣으면 그 이터레이터 내부 요소 하나 하나 함수를 적용시켜 준다는 의미다. 아래 예시는 배열의 모든 값을 제곱해주는 결과를 나타낸다.

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

print(list(map(lambda x: x**2, TIL_list)))
[1, 4, 9, 16, 25]

map() 을 이용하면 return으로 map object 를 리턴하므로 list로 바꿔준다. 또 다음과 같이 다중 이터러블을 넣어 줄 수 도 있다.

TIL_list1 = [1, 2, 3, 4, 5]
TIL_list2 = [1, 2, 3, 4, 5, 6]

print(list(map(lambda x, y: x + y, TIL_list1, TIL_list2)))
[2, 4, 6, 8, 10]

다중 이터러블을 넣을 경우 가장 짧은 이터러블을 기준으로 한다.

2.2 filter()

  • filter(function, iterable)

    function 이 참을 돌려주는 iterable 의 요소들로 이터레이터를 구축합니다. iterable 은 시퀀스, 이터레이션을 지원하는 컨테이너 또는 이터레이터 일 수 있습니다. functionNone 이면, 항등함수가 가정됩니다.

filter() 함수를 사용하면 function인자가 참으로하는 이터레이터의 요소들만 리턴을 해준다. 만약 function 인자가 None 이라면 항등함수로 가정한다. 말이 어려운데 이터레이터의 요소 중 거짓을 없애고 참 값만 리턴을 해준다.

print(list(filter(None, [True, False, False, True])))
[True, True]

lambda이용한 간단한 예시를 들어보자 변수 x 가 5보다 크고 10보다 작은 것들만 출력하기 위해서는 다음과 같은 lambda를 넣어주면 된다.

TIL_list = [1, 3, 5, 6, 8, 10, 4, 9, 2, 7]

print(list(filter(lambda x: 5 < x < 10, TIL_list)))
[6, 8, 9, 7]

filter() 함수는 이터러블을 하나만 가질 수 있다.

2.3 reduce()

  • reduce(function, iterable[, initializer])

    두 인자의 function을 왼쪽에서 오른쪽으로 iterable의 항목에 누적적으로 적용해서, 이터러블을 단일 값으로 줄입니다.

쉽게 말해 함수의 리턴을 각 이터러블에 적용해 단일 값으로 계속 줄여나가 최종적으로 하나의 값만을 취해주는 함수 이다. 이 때 x 는 누적값이며, y 는 이터러블에서 새롭게 갱신된 값이다. initializer 는 초깃값을 지정해주는 변수이며, 대략 reduce() 함수를 풀어보면 다음과 같다.

def reduce(function, iterable, initializer=None):
    it = iter(iterable)
    if initializer is None:
        value = next(it)
    else:
        value = initializer
    for element in it:
        value = function(value, element)
    return value

reduce() 와 lambda를 이용해 이터러블내부의 값을 더하는 간단한 예시는 다음과 같다.

from functools import reduce

TIL_list = [1, 3, 5, 6, 8, 10, 4, 9, 2, 7]

print(reduce(lambda x, y: x + y, TIL_list))
55

3. lambda에 관한 인식

위에서 언급했듯이 lambda는 일회성 함수로 한번 쓰이고 버려진다. 사실 함수라고 하기엔 docstiring 이나 annotations, statements 같은 여러가지들이 지원이 되지 않는다. 아래는 파이썬 창시자인 Guido van Rossum의 인터뷰 내용인데 lambda에 관해 언급을 다음과 같이 했다.

"Q. What feature of Python are you least pleased with?

Sometimes I've been too quick in accepting contributions, and later realized that it was a mistake. One example would be some of the functional programming features, such as lambda functions. lambda is a keyword that lets you create a small anonymous function; built-in functions such as map, filter, and reduce run a function over a sequence type, such as a list.

In practice, it didn't turn out that well. Python only has two scopes: local and global. This makes writing lambda functions painful, because you often want to access variables in the scope where the lambda was defined, but you can't because of the two scopes. There's a way around this, but it's something of a kludge. Often it seems much easier in Python to just use a for loop instead of messing around with lambda functions. map and friends work well only when there's already a built-in function that does what you want.

Guido van Rossum도 lambda에 대한 평가가 좋지 않은것을 확인할 수 있다. 실제 stackoverflow같은 곳에서도 lambda를 쓰기보다. list comprehension이나 for 구문을 이용하는 것이 더 직관적으로 보이고 한결 낫다는 주장도 있다(실제 lambda에서 제공하는 기능은 일반함수에서 구현 할 수 있으니까).

reference

🔗 파이썬 코딩도장

🔗 Stack Overflow

🔗 Python3.10.0 공식문서

0개의 댓글