Classmethod and Staticmethod#
Python의 클래스에서 사용되는 두 가지 다른 종류의 메서드 데코레이터
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| class MyClass:
class_var = 0 # 클래스 변수
def __init__(self):
self.instance_var = 0 # 인스턴스 변수
# 일반 인스턴스 메서드
def instance_method(self):
return f"instance method: {self.instance_var}"
# 클래스 메서드
@classmethod
def class_method(cls):
return f"class method: {cls.class_var}"
# 정적 메서드
@staticmethod
def static_method():
return "static method"
|
Classmethod#
@classmethod
데코레이터 사용- 첫 번째 매개변수로 클래스 자신(cls)을 자동으로 받음
- 클래스 변수에 접근 가능
- 상속 시 cls는 현재 클래스를 참조
주요 사용 사례#
대체 생성자(Alternative Constructor) 구현#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def from_string(cls, date_string):
year, month, day = map(int, date_string.split('-'))
return cls(year, month, day)
@classmethod
def from_timestamp(cls, timestamp):
import datetime
date = datetime.datetime.fromtimestamp(timestamp)
return cls(date.year, date.month, date.day)
# 사용 예시
date1 = Date.from_string('2024-03-20')
date2 = Date.from_timestamp(1710915600) # 2024-03-20의 타임스탬프
|
클래스 상태 관리#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| class Student:
total_students = 0 # 클래스 변수
def __init__(self, name):
self.name = name
Student.total_students += 1
@classmethod
def get_total_students(cls):
return cls.total_students
@classmethod
def reset_total_students(cls):
cls.total_students = 0
# 사용 예시
student1 = Student("John")
student2 = Student("Jane")
print(Student.get_total_students()) # 출력: 2
Student.reset_total_students()
print(Student.get_total_students()) # 출력: 0
|
Staticmethod#
@staticmethod
데코레이터 사용- 첫 번째 매개변수로 아무것도 자동으로 받지 않음
- 클래스/인스턴스 변수에 직접 접근 불가
- 유틸리티 함수처럼 독립적으로 동작
주요 사용 사례#
유틸리티 함수 구현#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| class MathOperations:
@staticmethod
def is_even(number):
return number % 2 == 0
@staticmethod
def is_prime(number):
if number < 2:
return False
for i in range(2, int(number ** 0.5) + 1):
if number % i == 0:
return False
return True
@staticmethod
def get_factors(number):
return [i for i in range(1, number + 1) if number % i == 0]
# 사용 예시
print(MathOperations.is_even(4)) # 출력: True
print(MathOperations.is_prime(7)) # 출력: True
print(MathOperations.get_factors(12)) # 출력: [1, 2, 3, 4, 6, 12]
|
헬퍼 메서드 구현#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| class FileProcessor:
def __init__(self, filename):
self.filename = filename
@staticmethod
def is_valid_file_format(filename):
return filename.endswith(('.txt', '.csv', '.json'))
@staticmethod
def get_file_extension(filename):
return filename.split('.')[-1] if '.' in filename else ''
def process_file(self):
if not self.is_valid_file_format(self.filename):
raise ValueError("Invalid file format")
# 파일 처리 로직…
# 사용 예시
print(FileProcessor.is_valid_file_format('data.txt')) # 출력: True
print(FileProcessor.get_file_extension('data.csv')) # 출력: csv
|
Classmethod와 Staticmethod 비교#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| class Example:
class_var = 10
def __init__(self):
self.instance_var = 5
# 인스턴스 메서드
def instance_method(self):
return self.instance_var, self.class_var
# 클래스 메서드
@classmethod
def class_method(cls):
return cls.class_var # 클래스 변수 접근 가능
# return self.instance_var # 인스턴스 변수 접근 불가
# 정적 메서드
@staticmethod
def static_method():
# 클래스/인스턴스 변수 직접 접근 불가
return "I am static"
|
사용 시 고려사항#
Classmethod 사용 시기#
- 클래스 상태를 수정하거나 접근해야 할 때
- 대체 생성자가 필요할 때
- 상속 시 다형성이 필요할 때
Staticmethod 사용 시기#
- 클래스/인스턴스 상태와 무관한 유틸리티 함수가 필요할 때
- 네임스페이스 조직화가 필요할 때
- 순수 함수가 필요할 때
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| class DataProcessor:
data_format = 'json' # 클래스 변수
def __init__(self, data):
self.data = data
# classmethod 사용이 적절한 경우
@classmethod
def change_data_format(cls, new_format):
if cls.is_valid_format(new_format): # staticmethod 호출
cls.data_format = new_format
return True
return False
# staticmethod 사용이 적절한 경우
@staticmethod
def is_valid_format(format_str):
return format_str.lower() in ['json', 'xml', 'yaml']
# 일반 인스턴스 메서드
def process(self):
if not self.is_valid_format(self.data_format):
raise ValueError("Invalid format")
# 데이터 처리 로직…
# 사용 예시
print(DataProcessor.is_valid_format('json')) # 출력: True
DataProcessor.change_data_format('xml') # 데이터 형식 변경
|
Self와 Cls#
기본 개념#
self: 인스턴스 메서드에서 인스턴스 자신을 참조
cls: 클래스 메서드에서 클래스 자신을 참조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| class ExampleClass:
class_variable = 0 # 클래스 변수
def __init__(self):
self.instance_variable = 0 # 인스턴스 변수
# 인스턴스 메서드
def instance_method(self):
return self.instance_variable
# 클래스 메서드
@classmethod
def class_method(cls):
return cls.class_variable
# 정적 메서드
@staticmethod
def static_method():
return "I am static"
|
메서드 종류별 특징과 사용법#
인스턴스 메서드 (self 사용)#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| class User:
def __init__(self, name):
self.name = name # 인스턴스 변수 설정
def say_hello(self): # 인스턴스 메서드
return f"Hello, I'm {self.name}"
def change_name(self, new_name): # 인스턴스 변수 수정
self.name = new_name
# 사용 예시
user = User("John")
print(user.say_hello()) # 출력: Hello, I'm John
user.change_name("Mike")
print(user.say_hello()) # 출력: Hello, I'm Mike
|
클래스 메서드 (cls 사용)#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| class DatabaseConnection:
connection_count = 0 # 클래스 변수
def __init__(self):
DatabaseConnection.connection_count += 1
@classmethod
def get_connection_count(cls): # 클래스 메서드
return cls.connection_count
@classmethod
def create_connection(cls): # 팩토리 메서드 패턴
return cls()
# 사용 예시
conn1 = DatabaseConnection()
conn2 = DatabaseConnection()
print(DatabaseConnection.get_connection_count()) # 출력: 2
|
정적 메서드 (self나 Cls 사용하지 않음)#
1
2
3
4
5
6
7
8
9
10
11
12
| class MathOperations:
@staticmethod
def add(x, y): # 정적 메서드
return x + y
@staticmethod
def is_positive(number): # 정적 메서드
return number > 0
# 사용 예시
print(MathOperations.add(5, 3)) # 출력: 8
print(MathOperations.is_positive(-1)) # 출력: False
|
Self와 Cls를 사용하는 상황 구분#
메서드 종류 | 데코레이터 | 첫 번째 매개변수 | 사용하는 경우 |
---|
인스턴스 메서드 | 없음 | self | 인스턴스 상태를 수정하거나 접근할 때 |
클래스 메서드 | @classmethod | cls | 클래스 상태를 수정하거나 접근할 때 |
정적 메서드 | @staticmethod | 없음 | 클래스/인스턴스 상태와 무관한 기능 구현 시 |
실제 사용 예시#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
| class Student:
school_name = "Python High School" # 클래스 변수
student_count = 0 # 클래스 변수
def __init__(self, name, age):
self.name = name # 인스턴스 변수
self.age = age # 인스턴스 변수
Student.student_count += 1
# 인스턴스 메서드
def introduce(self):
return f"Hi, I'm {self.name}, {self.age} years old"
# 클래스 메서드
@classmethod
def change_school_name(cls, new_name):
cls.school_name = new_name
# 클래스 메서드 - 대체 생성자
@classmethod
def from_string(cls, string):
name, age = string.split(',')
return cls(name, int(age))
# 정적 메서드
@staticmethod
def is_adult(age):
return age >= 18
# 사용 예시
# 1. 인스턴스 메서드 사용
student = Student("John", 20)
print(student.introduce()) # 출력: Hi, I'm John, 20 years old
# 2. 클래스 메서드 사용
Student.change_school_name("Python University")
print(Student.school_name) # 출력: Python University
# 3. 대체 생성자 사용
new_student = Student.from_string("Jane")
print(new_student.introduce()) # 출력: Hi, I'm Jane, 19 years old
# 4. 정적 메서드 사용
print(Student.is_adult(20)) # 출력: True
|
주의사항#
- self와 cls는 관례적인 이름이지만, 다른 이름을 사용할 수도 있다 (하지만 권장하지 않음)
- 인스턴스 메서드는 self를 통해 클래스 변수에도 접근할 수 있다
- 클래스 메서드는 인스턴스 변수에 접근할 수 없다
- 정적 메서드는 클래스/인스턴스 변수 모두에 접근할 수 없다
참고 및 출처#