본문 바로가기
CS

[Python] Callable이란?

by cuda 2022. 11. 25.

Callable 객체

호출 연산자인 ()는 사용자 정의 함수 이외의 다른 객체에도 사용할 수 있다.
호출할 수 있는 객체(Callable)인지 알아보려면 callable()내장 함수를 사용한다.
파이썬에는 다음과 같은 callable이 있다.

  • 사용자 정의 함수

    def 문이나 람다 표현식으로 생성
  • 내장 함수

    len()이나 time.strftime()처럼 C언어로 구현된 함수
  • 내장 메서드

    dict.get()처럼 C언어로 구현된 메서드
  • 메서드

    클래스 본체에 정의된 함수
  • 클래스

    호출될 때 클래스는 자신의 __new__()메서드를 실행해서 객체를 생성하고, __init__()으로
    초기화한 후, 최정적으로 호출자에 객체를 반환한다. 파이썬에서는 new 연산자가 없기 때문에 클래스를 호출하는 것은
    함수를 호출하는것과 동일하다.(일반적으로 클래스를 호출하면 해당 클래스의 객체가 생성되지만, __new__() 메서드를
    오버라이딩 하면 다르게 작동할 수 있다.)
  • 클래스 객체

    클래스가 __call__()메서드를 구현하면 이 클래스의 객체는 함수로 호출될 수 있다.
  • 제네레이터 함수

    yield키워드를 사용하는 함수나 메서드. 이 함수가 호출되면 제네레이터 객체를 반환한다.

파이썬에는 다양한 callable 형이 존재하기 때문에, callable() 내장 함수를 사용하여 호출할 수 있는 객체인지
판단하는 방법이 가장 안전하다. 아래의 예시를 확인해보자.

>>> abs, str, 13
(<built-in function abs>, <class 'str'>, 13)

>>> [callable(obj) for obj in (abs, str, 13)]
[True, True, False]

abs는 내장 함수, str은 클래스로써 callable형이며, 13은 callable형이 아니다.
이를 확인하기 위해 callable() 내장 함수를 이용하면, 실제로 ["True", "True", "False"] 가 출력됨을 확인할 수 있다.

사용자 정의 callable형

파이썬 함수가 실제 객체일 뿐만 아니라, 모든 파이썬 객체가 함수처럼 동작하게 만들 수 있다.
__call__() 인스턴스 메소드를 구현하면 모든 파이썬 객체를 함수처럼 동작하게 만들 수 있다.

import random


class BingoCage:
    def __init__(self, items):
        self._items = list(items)
        # self._items가 리스트이기에 shuffle()메서드 실행 보장
        random.shuffle(self._items)

    # 핵심 메서드
    def pick(self):
        try:
            return self._items.pop()
        except IndexError:
            # self._items가 비어있으면 사용자 정의 메시지를 담은 예외 발생시킴
            raise LookupError('pick from empty BingoCage')

    # bingo.pick()에 대한 단축 형태로 bingo() 정의
    def __call__(self):
        return self.pick()
>>> bingo = BingoCage(range(3))
>>> bingo.pick()
2
>>> bingo()
0
>>> callable(bingo)
True

BingoCage의 경우 객체를 함수처럼 호출할 때마다 항목을 하나 꺼낸 후 변경된 상태를 유지해야 하는데, __call__()메서드를 구현하면 이런 객체를 생성하기 쉽다.
이런 예로는 decorator가 있다. decorator는 함수이지만, 때때로 호출된 후의 상태를 기억할 수 있는 기능이 유용하게 사용된다.

reference : Fluent python - 한빛미디어

댓글