메서드 종류를 외우기보다, 이 메서드가 무엇에 접근해야 하는가를 먼저 보면 판단이 빠릅니다.
인스턴스 상태를 쓰는지, 클래스 자체를 다루는지, 상태 없이 관련 유틸만 묶는지에 따라 일반 메서드, @classmethod, @staticmethod가 갈립니다.
빠른 비교
class User:
def __init__(self, name: str) -> None:
self.name = name
@classmethod
def from_csv(cls, row: str) -> "User":
return cls(row.strip())
@staticmethod
def normalize(name: str) -> str:
return name.strip().title()문법
기본형은 인스턴스 메서드, 클래스 메서드, 정적 메서드 세 가지를 함께 보면 됩니다.
class Example:
def instance_method(self):
...
@classmethod
def class_method(cls):
...
@staticmethod
def static_method():
...메서드 선택
인스턴스 상태를 쓰면 일반 메서드 (self)
대부분의 메서드는 특정 객체 상태를 읽거나 바꾸기 때문에 self를 받는 인스턴스 메서드입니다.
class Counter:
def __init__(self) -> None:
self.value = 0
def inc(self) -> None:
self.value += 1이게 기준이고, classmethod와 staticmethod는 그 바깥의 특수한 경우입니다.
클래스 자체를 다루면 @classmethod
@classmethod는 첫 인자로 cls를 받습니다.
그래서 인스턴스 생성 규칙을 클래스 수준에서 정의할 때 유용합니다.
class User:
def __init__(self, name: str) -> None:
self.name = name
@classmethod
def from_csv(cls, row: str) -> "User":
return cls(row.strip())상속된 클래스에서도 cls가 맞게 전달되므로, 대체 생성자 패턴에 특히 자연스럽습니다.
상태를 안 쓰는 유틸이면 @staticmethod
@staticmethod는 self도 cls도 받지 않습니다.
클래스와 논리적으로 관련은 있지만 인스턴스/클래스 상태가 필요 없는 유틸 함수를 묶을 때 씁니다.
class User:
@staticmethod
def normalize(name: str) -> str:
return name.strip().title()굳이 클래스 안에 둘 필요가 없다면 모듈 함수가 더 나을 수도 있습니다.
구조 비교
애매하면 모듈 함수도 같이 검토한다
staticmethod가 항상 좋은 건 아닙니다.
클래스와 아주 강하게 묶이지 않는다면 그냥 모듈 함수가 더 읽기 쉬운 경우도 많습니다.
주의할 점
인스턴스 상태를 써야 하는데 @staticmethod로 만들면 self에 접근할 수 없습니다. 메서드 종류는 "어떤 상태를 쓰는가"로 결정해야 합니다.
# ❌ 인스턴스 속성을 써야 하는데 staticmethod 사용
class User:
def __init__(self, name):
self.name = name
@staticmethod
def greet():
return f"Hello, {self.name}"
# ✅ 인스턴스 메서드로 선언
class User:
def __init__(self, name):
self.name = name
def greet(self):
return f"Hello, {self.name}"참고 링크
2 sources