Python @staticmethod
@staticmethod의 목적은 "외부에서 호출 가능하게" 하는 것이 아니다. 외부 호출은 인스턴스를 만들면 어떤 메서드든 가능하기 때문.
핵심
"이 함수는 self도, cls도 필요 없다"는 선언.
Python 클래스 안에 함수를 정의하면 기본적으로 첫 번째 인자로 인스턴스(self)가 암묵적으로 바인딩된다. @staticmethod는 그 바인딩을 제거한다.
class Converter:
@staticmethod
def celsius_to_fahrenheit(c):
return c * 9/5 + 32
# 두 가지 모두 동작
Converter.celsius_to_fahrenheit(100)
Converter().celsius_to_fahrenheit(100)
왜 모듈 함수로 안 빼고 클래스 안에 두나?
기능적으로는 동일하다. 차이는 의미와 네임스페이스 — "이 함수는 이 클래스의 책임 범위 안에 있고, 인스턴스 상태는 필요 없다"는 것을 코드로 명시하는 것.
세 가지 메서드 비교
| | 첫 인자 | 접근 가능한 것 |
|---|---|---|
| 일반 메서드 | self (인스턴스) | 인스턴스 상태, 클래스 |
| @classmethod | cls (클래스) | 클래스 변수, 클래스 메서드 |
| @staticmethod | 없음 | 인자로 받은 것만 |
@classmethod는 팩토리 메서드 패턴에 자주 쓰인다 — cls를 통해 서브클래스를 인식할 수 있기 때문. @staticmethod는 그마저도 필요 없는 순수 유틸리티 함수.
왜 클래스 밖에 안 두나?
기능적으로는 모듈 레벨 함수와 완전히 동일하게 동작한다. 차이는 의미적 소속뿐.
"이메일 검증은 User의 책임" → User 클래스 안에 두는 것이 구조적으로 명확하다. C++로 치면 관련 없는 free function을 namespace 안에 넣는 감각과 같다.
사용 방법
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
def to_fahrenheit(self): # 인스턴스 메서드 — self.celsius 씀
return Temperature.c_to_f(self.celsius)
@staticmethod
def c_to_f(c): # 변환 공식 자체는 인스턴스 상태 불필요
return c * 9/5 + 32
# 클래스 이름으로 직접 호출
Temperature.c_to_f(0) # → 32.0
# 인스턴스를 통해서도 호출 가능 (근데 어색해서 잘 안 씀)
t = Temperature(100)
t.c_to_f(0) # → 32.0
t.to_fahrenheit() # → 212.0 (내부에서 staticmethod 호출)
한 줄 기준
"인스턴스 없이도 쓸 수 있고, 이 클래스와 의미적으로 관련 있다" →
@staticmethod
성능 vs 가독성
@staticmethod는 호출 시 bound method 객체 생성을 건너뛰어서 미세하게 빠르다. 하지만 수십 나노초 수준 — 병목이 될 수 없다.
진짜 이유는:
- 의도 표현: 함수 내부를 읽지 않아도 "인스턴스 상태 안 건드림"을 즉시 알 수 있다
- 구조적 가이드레일:
self가 없으니 실수로 인스턴스 상태를 건드리는 코드가 들어갈 수 없다
C++에서 멤버 함수에 const를 붙이는 감각과 같다 — 성능보다 "이 함수는 상태를 안 바꾼다"는 계약을 코드에 새기는 것.