본문 바로가기

진리는어디에/Python

[Python] 당신이 모를 수도 있는 함수에 대한 4가지 고급 트릭

본 포스트는 Python Land’s deep dive on functions의 내용을 한글로 번역한 내용이다.

기본 파이썬 문법을 이해하고 있는 사람을 대상으로 하지만 각 섹션들마다 자세한 이해에 도움이 될만한 글들을 링크 걸어 두었으니 조금만 노력을 들이면 초보자들도 이해 할 수 있을것이라 생각한다.

하지만 아직 시작 단계이신 분들께는 여전히 어려운 주제일 수 있다. 그런 분들은 이 글과 함께 '파이썬 기초부터 시작하기'를 읽어 볼 것을 권해드린다.

당신은 함수의 키워드 아규먼트를 강제하거나, 함수 데코레이터를 생성하거나, 익명(람다) 함수를 생성하거나, 배열 또는 딕셔너리를 함수의 인수로 언팩(unpack)하는 방법을 알고 있습니까? 본 포스트는 파이썬 함수에 관한 4가지 고급 트릭을 다루고 있습니다.

1. 키워드 아규먼트 강제하기

키워드 인수에는 다음과 같은 몇 가지 장점이 있습니다.

  • 인자를 순서에 따라 넘겨줘야할 필요가 없습니다 - 순서가 아니라 이름이 중요합니다
  • 키워드 인수는 명확성을 제공합니다. 함수 자체를 살펴보지 않고도 키워드의 이름만 보고 인수가 무엇에 사용되었는지 추측할 수 있습니다.

위 사항들은 아마 알고 계셨을지도 모릅니다. 하지만 키워드 아규먼트를 강제할 수도 있다는 것은 모르셨을지도 모릅니다. 이에 대한 세부 사항은 PEP 3202에 설명되어 있지만, 결론은 키워드 아규먼트로 강제하려는 인수 앞에 별표를 사용하면 됩니다. 또는 함수의 인자 리스트 가장 앞에 별표를 사용함으로써 모든 인수들이 키워드 아규먼트가 되도록 합니다.

>>> def f(*, a, b):
...     print(a, b)
...
>>> f(1, 2)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: f() takes 0 positional 
           arguments but 2 were given
>>> f(a=1, b=2)
1 2
>>>

키워드 아규먼트에 대한 보다 자세한 사항은 [여기]에 정리 되어 있습니다.

2. 함수 언패킹을 위해 * 와 ** 사용하기

일부 함수에는 긴 인수 목록이 필요합니다. 이것은 완전히 피해야 하지만(예: 데이터 클래스 사용) 항상 프로그래머 마음대로 되는 것은 아닙니다. 이러한 경우 차선책은 명명된 모든 인수로 딕셔너리 자료구조를 만들고 함수에 전달하는 것입니다. 일반적으로 코드를 더 읽기 쉽게 만듭니다.

딕셔너리 인자에 ** 접두사를 사용하여 네임드 키워드와 함께 사용할 딕셔너리를 언팩(unpack) 할 수 있습니다.

>>> def f(a, b):
...     print(a, b)
...
>>> args = { "a": 1, "b": 2 }
>>> f(**args)
1 2

마찬가지로 단일 *를 사용하여 배열의 압축을 풀고 그 내용을 함수에 대한 위치 인수(positional argument)로 제공할 수 있습니다.

>>> def f(a, b, c):
...    print(a, b, c)
...
>>> l = [1, 2, 3]
>>> f(*l)
1 2 3

인자의 패킹과 언패킹은 다음 두 포스트 참고하세요.

3. 데코레이터로 함수 꾸미기

데코레이터는 기존의 코드를 수정하지 않고 함수의 동작을 수정하는 함수 래퍼입니다. 데코레이터에는 많은 사용 사례가 있으며, 특히 Flask와 같은 프레임워크를 사용해본 경험이 있다면 데코레이터인줄도 모르고 사용했을 수도 있습니다(제가 그랬습니다).

나만의 데코레이터를 만들어 봅시다. 예상보다 간단하고 언젠가는 유용할 것입니다.

def print_argument(func):
    def wrapper(the_number):
        print("Argument for", func.__name__, "is", the_number)
        return func(the_number)
    
    return wrapper

@print_argument
def add_one(x):
    return x + 1

print(add_one(1))

print_argument 내부에서 래퍼 함수를 정의합니다. 이 함수는 호출된 함수의 인수와 이름을 출력합니다. 그런 다음 실제 함수를 실행하고 함수가 정기적으로 호출된 것처럼 결과를 반환합니다.

@print_argument를 사용하여 데코레이터를 함수에 적용합니다. 아마도 이것은 말할 필요가 없겠지만 이 데코레이터는 다른 기능에도 재사용할 수 있습니다. 스크립트의 출력은 다음과 같습니다.

Argument for add_one is 1
2

데코레이터(Decorator)에 대한 보다 자세한 사항은 [여기]에 정리 되어 있습니다.

4. 이름 없는 함수(람다)

때로는 함수의 이름을 지정하는 노력을 들일 필요가 없을 때가 있습니다. 예를 들어 함수가 한 번만 사용된다고 확신하는 경우입니다. 이러한 경우 파이썬은 익명 함수(람다 함수라고도 함)를 제공합니다. 람다 함수를 변수에 할당하여 함수를 정의하는 간결한 방법을 만들 수 있습니다.

>>> add_one = lambda x: x + 1
>>> add_one(3)
4

함수를 인수로 사용해야 할 때 더 흥미로워집니다. 이러한 경우 함수는 종종 한 번만 사용됩니다. 아시다시피 map은 iterable 객체의 모든 요소에 함수를 적용합니다. map을 호출할 때 람다를 사용할 수 있습니다.

>>> numbers = [1, 2, 3, 4]
>>> times_two = map(lambda x: x * 2, numbers)
>>> list(times_two)
[2, 4, 6, 8]
>>>

사실, 이것은 여러분이 자주 보게 될 패턴입니다. 반복 가능한 개체의 각 요소에 비교적 간단한 작업을 적용해야 할 때 map()을 람다 함수와 함께 사용하면 간결하고 효율적입니다.

함수를 인수로 사용하는 일급 객체와 람다 함수에 대한 자세한 설명은 아래 링크를 참고 하십시오.

부록 1. 같이 읽으면 좋은 글

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!