본문 바로가기
스터디 공간

[Python] 고위함수(higher-order function) map(), filter(), lambda() / namedtuple 사용하기

by 재스민맛 2022. 6. 24.
반응형

map() 함수

map() 함수는 두 번째 인수의 연속된 요소에 첫 번째 인수(함수)를 적용한 결과를 가지는 반복 가능형 객체를 반복합니다.

list(map(lambda x:x, range(1, 5)))

# -> [1, 2, 3, 4]

map()함수의 첫 번째 인자인 lambda 함수에  두 번째 인자인 range(1, 5) 적용한 결과로 [1, 2, 3, 4]를 반환합니다.

map는 lazy evaluation으로서, 실제로 계산이 필요할때 연산을 하므로 메모리 절약에 도움이 됩니다.

그래서 list로 감싸줄 때 실제 연산을 하여, [1, 2, 3, 4]를 반환하게 됩니다.

 

 

다른 예제를 통해서 map함수를 알아보겠습니다.

def factorial(n):
    return 1 if n<2 else n*factorial(n-1)

list(map(factorial, range(1, 11)))

# [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

map의 첫 번째 인자로 factorial함수를 전달하였고, 두 번째 인자로 range(1, 11)를 적용하였습니다.

map함수 자체는 아무런 연산을 하지 않고 실제 계산이 필요할때 연산을 하는 동작이 일어나므로, list를 씌워주어 실제 연산동작을 하도록 합니다.

 

 

filter() 함수

filter는 말그대로 필터입니다. 특정 값을 필터링하여 바깥으로 내보내던가, 아니면 내보내지 않을 수 있습니다.

예시를 통해서 알아보겠습니다.

a = [1, 5, 10, 12, 18, 19, 21, 25, 28, 30, 31]

# odd number만 끄집어 내고 싶다면?
list(filter(lambda n:n%2==0, a))
# >> [10, 12, 18, 28, 30]


# odd number만 factorial 함수의 인자로 넣고 싶다면?
list(map(factorial, (filter(lambda n:n%2==0, a))))
# >> [3628800, 479001600, 6402373705728000, 304888344611713860501504000000, 265252859812191058636308480000000]

동작방법이 list comprehension과 유사하다는 것을 알 수 있으며, 

filter과 map 함수는 가독성은 그에 비해 떨어지는 단점이 있습니다만,, 그래도 사용 방법을 익혀두면 좋습니다.

 

 

lambda() : 익명함수

코드는 기본적으로 가독성이 좋아야하므로, 람다는 단순한 구문이 아니라면 사용하지 않는 것이 좋습니다.

고위 함수의 인수로 사용하는 경우를 제외하고 람다함수는 가독성을 해치는 경우가 많기 때문에 주의하여 사용하도록 합니다.

유용하게 쓰는 경우는 map, filter 내의 첫 번째 인자 혹은 sorted 등에서 key로 람다함수를 넣는 것입니다.

PC = ['computer', 'mouse', 'keyboard', 'monitor', 'printer']

sorted(PC, key=lambda x:len(x)) # sorted(PC, key=len)과 같은 코드입니다.

# >> ['mouse', 'monitor', 'printer', 'computer', 'keyboard']

 

collections.namedtuple

from collections import namedtuple
from pprint import pprint
import random

card = namedtuple('Card', 'mark number')

class Deck:
    '''Deck'''
    def __init__(self):
        self.deck = [card(mark, number) for mark in ['Heart', 'Clover', 'Diamond', 'Spade'] for number in list(range(2, 11))+['J', 'Q', 'K', 'A']]
    
    def __getitem__(self, position):
        return self.deck[position]

    def pick_random(self, n):
        random.shuffle(self.deck)
        return random.sample(self.deck, n)

    def __repr__(self):
        return str(self.deck)
    
    def __len__(self):
        return len(self.deck)

deck1 = Deck()
pprint(deck1) # __repr__을 통해서 표현됨
print()
deck1.pick_random(3) # random 모듈을 사용하여, 3장을 랜덤하게 뽑는다.

namedtupled을 이용하여, 카드 덱을 만들어 보았습니다.

card라는 namedtuple은 표시와 숫자를 가지고 있으며, Deck이라는 클래스 내부에서 사용하도록 하였습니다.

"__repr__" 은 representation으로 클래스 객체가 표현되는 모습을 보여줍니다.

"__str__"과 매우 유사하지만, __str__ 은 기본적으로 print문에서 동작하는 모습을 표현하도록 합니다.

"__len__" 은 list와 동일하게 내부 개수를 세는 len동작을 먹도록 하는 것입니다.

 

반응형

댓글