Python 모듈을 호출 가능하게 만들기: Cadule 소개

발행: (2025년 12월 27일 오전 12:02 GMT+9)
5 min read
원문: Dev.to

Source: Dev.to

Making Python Modules Callable: Introducing Cadule에 대한 표지 이미지

Python 코드를 작성할 때, Node.js에서 제공하는 기능이 그리워지는 경우가 종종 있습니다. 바로 모듈을 require 하면 바로 호출 가능한 형태가 되는 기능이죠. Node.js에서는 모듈에서 함수를 내보내고 바로 호출할 수 있습니다:

const messUpThings = require('./mess-up-things');
messUpThings(); // Works!

이 패턴을 좋아하지 않는 개발자도 있겠지만, 합리적인 사용 사례가 존재합니다.

The Problem

mess_up_things처럼 스스로를 설명하는 이름을 가진 헬퍼 함수를 작성해야 하는 상황을 생각해 보세요. 함수 이름 자체가 무엇을 하는지 알려줍니다. 선택지는 다음과 같습니다:

  • util 혹은 helper 모듈을 만든다: util.py 혹은 helper.py에 넣는다. 많은 개발자, 특히 Go 개발자들은 이런 일반적인 이름을 꺼려하고 더 설명적인 패키지 이름을 선호합니다.
  • 전용 파일을 만든다: mess_up_things.py에 넣는다. 그러면 다음과 같이 다소 장황한 import 문을 써야 합니다:
from mess_up_things import mess_up_things

이런 반복은 불필요하게 느껴집니다. 다음과 같이 할 수 있다면 얼마나 좋을까요?

import mess_up_things
mess_up_things()

Exploring Solutions

Python의 매직 메서드에 익숙하다면, __call__ 메서드를 가진 객체는 호출 가능해진다는 것을 알 수 있습니다. 모듈은 types.ModuleType의 인스턴스이며 __getattr__ 같은 매직 메서드를 지원하므로, 모듈에 직접 __call__ 메서드를 정의할 수 있지 않을까 생각해 볼 수 있습니다.

안타깝게도 Python은 기본적으로 이를 지원하지 않습니다. 실제로 모듈 수준의 __call__ 지원을 제안한 PEP 713이 있었지만, 거절되었습니다.

하지만 다음과 같은 트릭을 이용하면 원하는 동작을 구현할 수 있습니다:

import sys

class MyModule(sys.modules[__name__].__class__):
    def __call__(self):
        print("Messing up things...")

sys.modules[__name__].__class__ = MyModule

이 코드는 런타임에 모듈의 __class__를 동적으로 교체함으로써 동작합니다. 하지만 매번 이 보일러플레이트 코드를 복사‑붙여넣고 싶지는 않겠죠?

Enter Cadule

이 보일러플레이트를 매번 작성하지 않도록, 저는 Cadule(Callable [Mo]dule Less의 약자)이라는 패키지에 메커니즘을 캡슐화했습니다.

Installation

pip install cadule

Usage

mess_up_things.py 파일을 다음과 같이 작성합니다:

import cadule

@cadule
def __call__():
    print("Messing up things...")

그런 다음 Python REPL이나 다른 스크립트에서:

>>> import mess_up_things
>>> mess_up_things()
Messing up things...
>>> callable(mess_up_things)
True

인자를 전달하거나 반환값을 줄 수도 있습니다:

import cadule

@cadule
def __call__(target):
    return f"Messing up {target}!"
>>> import mess_up_things
>>> mess_up_things("the database")
'Messing up the database!'

When to Use It

Cadule은 특히 다음과 같은 경우에 유용합니다:

  • 단일 목적 모듈: 모듈의 주요 목적이 하나의 함수를 노출하는 경우.
  • DSL 및 유창한 인터페이스: 보다 자연스러운 API를 만들고 싶을 때.
  • 스크립트와 유틸리티: 커맨드‑라인 도구를 직관적으로 사용할 수 있게 할 때.

GitHub:

Back to Blog

관련 글

더 보기 »

Python 시작하기 (10부): 함수 사용

함수 사용하기 이 기사에서는 함수에 대해 배웁니다. 함수를 사용하면 특정 프로세스를 재사용하고 더 깔끔하고 유지보수가 쉬운 코드를 작성할 수 있습니다....

내 간단한 틱택토 게임

Codecademy의 포트폴리오 프로젝트 시리즈의 일환으로, 터미널에서 완전히 실행되는 인터랙티브 Tic‑Tac‑Toe 게임을 만들었습니다. 이것은 제 첫 번째 완전한 Python…