파이썬에서 클래스를 다루다 보면 @classmethod라는 데코레이터(Decorator)를 만나게 됩니다. 이는 @staticmethod나 일반 인스턴스 메서드(Instance Method)와는 명확히 구분되는 고유한 목적을 가집니다.
이 글에서는 @classmethod가 무엇인지, 그리고 @staticmethod 및 인스턴스 메서드와 비교하여 어떤 상황에서 어떻게 사용해야 하는지 명확하게 알아보겠습니다.
1. 메서드의 세 가지 유형: Instance vs. Class vs. Static
파이썬 클래스에는 기본적으로 세 가지 유형의 메서드가 존재합니다. 이들의 가장 큰 차이는 메서드가 첫 번째 인자로 무엇을 받느냐에 있습니다.
class MyClass:
# 1. 인스턴스 메서드 (Instance Method)
def instance_method(self, arg1):
# 'self'는 클래스의 인스턴스를 받습니다.
# 인스턴스 속성(self.x)에 접근하고 수정할 수 있습니다.
print(f"Instance method called with {self} and {arg1}")
# 2. 클래스 메서드 (Class Method)
@classmethod
def class_method(cls, arg1):
# 'cls'는 클래스 자체(MyClass)를 받습니다.
# 클래스 속성에 접근하거나,
# 인스턴스를 생성하는 '팩토리' 역할을 할 때 주로 사용됩니다.
print(f"Class method called with {cls} and {arg1}")
# 3. 정적 메서드 (Static Method)
@staticmethod
def static_method(arg1):
# 'self'나 'cls'를 받지 않습니다.
# 클래스나 인스턴스 상태와는 무관한 유틸리티 함수입니다.
# 이 함수는 클래스 내부에 '속해있을' 뿐입니다.
print(f"Static method called with {arg1}")
# 메서드 호출 예시
obj = MyClass()
# 인스턴스 메서드 (인스턴스를 통해 호출)
obj.instance_method("Hello")
# 클래스 메서드 (클래스 또는 인스턴스를 통해 호출 가능)
MyClass.class_method("World")
obj.class_method("World") # 이것도 가능하지만, 클래스로 호출하는 것이 명확합니다.
# 정적 메서드 (클래스 또는 인스턴스를 통해 호출 가능)
MyClass.static_method("Python")
obj.static_method("Python")
한눈에 비교하기
| 구분 | 첫 번째 인자 | 접근 대상 | 주요 용도 |
|---|---|---|---|
| 인스턴스 메서드 | self (인스턴스) |
인스턴스 속성 (self.name) |
객체의 상태를 조작하거나 접근 |
| 클래스 메서드 | cls (클래스) |
클래스 속성 (cls.count) |
대체 생성자 (팩토리) |
| 정적 메서드 | 없음 | 없음 | 클래스와 논리적으로 관련 있는 유틸리티 함수 |
2. @classmethod의 핵심 활용: 팩토리 메서드
@classmethod의 가장 중요하고 일반적인 사용 사례는 "대체 생성자(Alternative Constructor)" 또는 "팩토리 메서드(Factory Method)"를 정의하는 것입니다.
기본 생성자인 __init__은 보통 명확한 인자들을 받아 객체를 초기화합니다. 하지만 때로는 다른 방식(예: 문자열 파싱, 딕셔너리, 특정 계산 값)으로 객체를 생성해야 할 필요가 있습니다.
@classmethod를 사용하면 __init__ 외에 클래스 인스턴스를 반환하는 또 다른 '진입점'을 만들 수 있습니다.

예제: 날짜 문자열로 Person 객체 생성하기
Person 클래스가 name과 age를 받는다고 가정해봅시다. 만약 '이름-출생연도' 형식의 문자열로도 객체를 생성하고 싶다면 어떻게 해야 할까요?
import datetime
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"안녕하세요, 저는 {self.name}이고 {self.age}살입니다.")
@classmethod
def from_birth_year(cls, name, birth_year):
"""
출생 연도를 받아 나이를 계산하여 Person 인스턴스를 생성합니다.
"""
current_year = datetime.datetime.now().year
age = current_year - birth_year
# 'cls'는 Person 클래스 자체를 가리킵니다.
# return Person(name, age)와 동일하지만,
# 'cls'를 사용하면 상속 시 이점을 가집니다. (아래에서 설명)
return cls(name, age)
# 기본 생성자 사용
person1 = Person("Alice", 30)
person1.greet()
# @classmethod로 만든 대체 생성자 사용
person2 = Person.from_birth_year("MadHatter", 1995)
person2.greet()
출력 결과:
안녕하세요, 저는 Alice이고 30살입니다.
안녕하세요, 저는 MadHatter이고 30살입니다. (현재 연도 2025 기준)
위 예제에서 from_birth_year 메서드는 cls라는 인자를 통해 Person 클래스 자체에 접근합니다. 그리고 계산된 age를 사용하여 cls(name, age)를 호출, 이는 곧 Person(name, age)를 호출하는 것과 같으며 새로운 Person 인스턴스를 반환합니다.
3. @classmethod와 상속
"그냥 Person(...)을 호출하면 되지, 왜 굳이 cls(...)를 사용하나요?"
@classmethod의 진정한 힘은 상속에서 드러납니다. cls는 현재 메서드가 호출된 _바로 그 클래스_를 가리킵니다.
Person을 상속받는 Student 클래스를 만든다고 가정해봅시다.
class Student(Person):
def __init__(self, name, age, major):
super().__init__(name, age) # 부모 클래스의 __init__ 호출
self.major = major
def greet(self):
# 메서드 오버라이딩
print(f"안녕하세요, 저는 {self.major} 전공 {self.name}이고 {self.age}살입니다.")
# Student 클래스에서 부모의 @classmethod를 호출합니다.
student1 = Student.from_birth_year("Jhon", 2005, "컴퓨터공학")
# 앗, TypeError가 발생합니다!
# Student.from_birth_year를 호출하면
# Person.from_birth_year가 실행되고,
# 이때 'cls'는 'Student'가 됩니다.
# 즉, return cls(name, age)는 return Student(name, age)가 됩니다.
# 하지만 Student의 __init__은 'major' 인자가 추가로 필요합니다.
위 코드는 Student의 __init__이 major를 필요로 하기 때문에 에러가 납니다. 하지만 핵심은 cls가 Person이 아닌 Student를 가리켰다는 점입니다.
만약 from_birth_year가 @staticmethod였거나, 내부에서 Person(name, age)을 하드코딩했다면, Student.from_birth_year를 호출해도 Student 객체가 아닌 Person 객체가 반환되었을 것입니다.
@classmethod는 cls를 통해 자식 클래스가 호출하더라도 올바른 자식 클래스의 인스턴스를 생성하도록 보장합니다. (물론 위 예처럼 자식 클래스의 __init__ 시그니처가 바뀐다면 from_birth_year도 오버라이딩해야 합니다.)
4. 정리
@classmethod에 대해 요약하자면 다음과 같습니다.
-
@classmethod는cls(클래스 자체)를 첫 번째 인자로 받습니다. -
주된 용도는 '대체 생성자 (팩토리 메서드)'입니다.
__init__외에 객체를 생성하는 다양한 방법을 제공할 때 사용합니다. -
상속과 함께 사용할 때 강력합니다. 자식 클래스에서 호출해도
cls는 올바른 자식 클래스를 가리켜, 해당 클래스의 인스턴스를 생성합니다.
@staticmethod는 클래스/인스턴스 상태가 전혀 필요 없는 유틸리티 함수에, @classmethod는 클래스 자체에 접근해야 하는 팩토리 메서드에, 그리고 일반 인스턴스 메서드는 객체의 상태(self)를 다룰 때 사용한다는 것을 기억하면 코드를 훨씬 더 명확하고 파이썬답게 작성할 수 있습니다.
댓글이 없습니다.