포스트

[Python 100일 챌린지] Day 34 - 클래스 변수와 클래스 메서드

[Python 100일 챌린지] Day 34 - 클래스 변수와 클래스 메서드

지금까지 배운 메서드는 모두 “개별 객체”에만 작동했는데, 모든 객체가 공유하는 기능은 어떻게 만들까요? 🤔 ──예를 들어 “지금까지 생성된 학생 수”는 개별 학생이 아니라 Student 클래스 전체가 알아야 하는 정보입니다! 😊

은행 계좌를 생각해보세요. 각 계좌의 잔액은 인스턴스 변수지만, “전체 계좌 수”, “기준 금리” 같은 건 모든 계좌가 공유하는 정보죠.

이럴 때 필요한 게 클래스 변수클래스 메서드입니다! 객체가 아닌 클래스 자체를 다루는 강력한 도구를 배웁니다! 💡

🎯 오늘의 학습 목표

⭐⭐⭐ (35-45분 완독)

📚 사전 지식


🎯 학습 목표 1: 클래스 메서드와 정적 메서드 이해하기

클래스 변수 vs 인스턴스 변수

인스턴스 변수 복습

각 객체가 독립적으로 가지는 변수입니다.

1
2
3
4
5
6
7
8
9
10
class Dog:
    def __init__(self, name, age):
        self.name = name  # 인스턴스 변수
        self.age = age    # 인스턴스 변수

dog1 = Dog("멍멍이", 3)
dog2 = Dog("바둑이", 5)

print(dog1.name, dog1.age)  # 멍멍이 3
print(dog2.name, dog2.age)  # 바둑이 5

클래스 변수

모든 인스턴스가 공유하는 변수입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Dog:
    species = "Canis familiaris"  # 클래스 변수 (모든 개는 같은 종)

    def __init__(self, name, age):
        self.name = name
        self.age = age

dog1 = Dog("멍멍이", 3)
dog2 = Dog("바둑이", 5)

# 모든 인스턴스가 같은 값 공유
print(dog1.species)  # Canis familiaris
print(dog2.species)  # Canis familiaris
print(Dog.species)   # Canis familiaris (클래스로 직접 접근)

# 클래스 변수 변경 - 모든 인스턴스에 영향!
Dog.species = "개과"
print(dog1.species)  # 개과
print(dog2.species)  # 개과

중요한 차이점

1
2
3
4
5
6
7
8
9
10
11
12
13
class Counter:
    count = 0  # 클래스 변수

    def __init__(self, name):
        self.name = name    # 인스턴스 변수
        Counter.count += 1  # 클래스 변수 증가

c1 = Counter("첫번째")
c2 = Counter("두번째")
c3 = Counter("세번째")

print(f"{Counter.count}개 생성됨")  # 총 3개 생성됨
print(c1.name, c2.name, c3.name)  # 첫번째 두번째 세번째

🎯 학습 목표 2: @classmethod 데코레이터 사용법 배우기

클래스 변수 주의사항

실수 1: 인스턴스로 클래스 변수 변경

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Example:
    shared = "공유 값"

    def __init__(self, name):
        self.name = name

obj1 = Example("첫번째")
obj2 = Example("두번째")

# ❌ 잘못된 방법 - 인스턴스 변수를 만들어버림!
obj1.shared = "변경된 값"

print(obj1.shared)      # 변경된 값 (obj1의 인스턴스 변수)
print(obj2.shared)      # 공유 값 (클래스 변수)
print(Example.shared)   # 공유 값 (클래스 변수)

# ✅ 올바른 방법 - 클래스로 변경
Example.shared = "정말 변경된 값"
print(obj1.shared)  # 변경된 값 (인스턴스 변수가 우선)
print(obj2.shared)  # 정말 변경된 값 (클래스 변수)

실수 2: 가변 객체를 클래스 변수로 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class BadExample:
    items = []  # ❌ 위험! 모든 인스턴스가 같은 리스트 공유

    def __init__(self, name):
        self.name = name

    def add_item(self, item):
        self.items.append(item)  # 클래스 변수에 추가됨!

obj1 = BadExample("첫번째")
obj2 = BadExample("두번째")

obj1.add_item("A")
obj2.add_item("B")

print(obj1.items)  # ['A', 'B'] (의도하지 않음!)
print(obj2.items)  # ['A', 'B'] (의도하지 않음!)

해결책:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class GoodExample:
    def __init__(self, name):
        self.name = name
        self.items = []  # ✅ 인스턴스 변수로!

    def add_item(self, item):
        self.items.append(item)

obj1 = GoodExample("첫번째")
obj2 = GoodExample("두번째")

obj1.add_item("A")
obj2.add_item("B")

print(obj1.items)  # ['A']
print(obj2.items)  # ['B']

🎨 클래스 메서드 (@classmethod)

클래스 메서드는 클래스 자체를 다루는 메서드입니다.

기본 문법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass:
    class_variable = 0

    @classmethod
    def class_method(cls):
        """클래스 메서드: 첫 번째 매개변수는 cls (클래스 자신)"""
        return cls.class_variable

# 클래스로 호출
result = MyClass.class_method()

# 인스턴스로도 호출 가능 (하지만 클래스로 호출 권장)
obj = MyClass()
result = obj.class_method()

💡 cls vs self:

  • self: 인스턴스 자신
  • cls: 클래스 자신

실전 예제 1: 객체 카운터

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
class Employee:
    """직원 정보를 관리하는 클래스"""

    employee_count = 0  # 클래스 변수

    def __init__(self, name, department):
        """생성자"""
        self.name = name
        self.department = department
        Employee.employee_count += 1

    @classmethod
    def get_employee_count(cls):
        """클래스 메서드: 총 직원 수 반환"""
        return cls.employee_count

    @classmethod
    def reset_count(cls):
        """클래스 메서드: 카운터 초기화"""
        cls.employee_count = 0
        print("✅ 직원 수가 초기화되었습니다.")

    def introduce(self):
        """인스턴스 메서드"""
        return f"{self.name} ({self.department})"

# 사용
emp1 = Employee("홍길동", "개발팀")
emp2 = Employee("김철수", "디자인팀")
emp3 = Employee("이영희", "기획팀")

# 클래스 메서드 호출
print(f"총 직원 수: {Employee.get_employee_count()}")  # 3명

# 인스턴스 메서드 호출
print(emp1.introduce())  # 홍길동 (개발팀)

# 카운터 초기화
Employee.reset_count()
print(f"총 직원 수: {Employee.get_employee_count()}")  # 0명

실행 결과:

1
2
3
4
총 직원 수: 3명
홍길동 (개발팀)
✅ 직원 수가 초기화되었습니다.
총 직원 수: 0명

실전 예제 2: 팩토리 메서드

클래스 메서드를 사용하면 다양한 방식으로 객체를 생성할 수 있습니다.

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
from datetime import datetime

class Person:
    """사람 정보를 관리하는 클래스"""

    def __init__(self, name, birth_year):
        """일반 생성자"""
        self.name = name
        self.birth_year = birth_year

    @classmethod
    def from_birth_date(cls, name, birth_date):
        """팩토리 메서드: 생년월일로 생성"""
        # birth_date 형식: "YYYY-MM-DD"
        year = int(birth_date.split('-')[0])
        return cls(name, year)

    @classmethod
    def from_age(cls, name, age):
        """팩토리 메서드: 나이로 생성"""
        current_year = datetime.now().year
        birth_year = current_year - age
        return cls(name, birth_year)

    def get_age(self):
        """나이 계산"""
        current_year = datetime.now().year
        return current_year - self.birth_year

    def introduce(self):
        """자기소개"""
        return f"{self.name} ({self.get_age()}살, {self.birth_year}년생)"

# 다양한 방식으로 객체 생성
person1 = Person("홍길동", 1990)
person2 = Person.from_birth_date("김철수", "1995-03-15")
person3 = Person.from_age("이영희", 25)

print(person1.introduce())
print(person2.introduce())
print(person3.introduce())

실행 결과:

1
2
3
홍길동 (35살, 1990년생)
김철수 (30살, 1995년생)
이영희 (25살, 2000년생)

실전 예제 3: 설정 관리 클래스

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
45
46
47
48
49
50
class Config:
    """애플리케이션 설정을 관리하는 클래스"""

    _instance = None  # 싱글톤 패턴용
    _settings = {
        "debug": False,
        "language": "ko",
        "timeout": 30
    }

    @classmethod
    def get(cls, key, default=None):
        """설정 값 가져오기"""
        return cls._settings.get(key, default)

    @classmethod
    def set(cls, key, value):
        """설정 값 저장"""
        cls._settings[key] = value
        print(f"{key} = {value}")

    @classmethod
    def update(cls, **kwargs):
        """여러 설정 한번에 업데이트"""
        for key, value in kwargs.items():
            cls._settings[key] = value
        print(f"{len(kwargs)}개 설정이 업데이트되었습니다.")

    @classmethod
    def print_all(cls):
        """모든 설정 출력"""
        print("\n" + "="*40)
        print("현재 설정")
        print("="*40)
        for key, value in cls._settings.items():
            print(f"{key}: {value}")
        print("="*40 + "\n")

# 사용 - 인스턴스 생성 없이 사용!
Config.print_all()

Config.set("debug", True)
Config.set("timeout", 60)

Config.update(language="en", max_connections=100)

Config.print_all()

print(f"Debug 모드: {Config.get('debug')}")
print(f"언어: {Config.get('language')}")

실행 결과:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
========================================
현재 설정
========================================
debug: False
language: ko
timeout: 30
========================================

✅ debug = True
✅ timeout = 60
✅ 2개 설정이 업데이트되었습니다.

========================================
현재 설정
========================================
debug: True
language: en
timeout: 60
max_connections: 100
========================================

Debug 모드: True
언어: en

🎯 학습 목표 3: @staticmethod 데코레이터 사용법 배우기

정적 메서드는 클래스나 인스턴스와 무관한 독립적인 함수입니다.

@staticmethod vs @classmethod vs 인스턴스 메서드

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
class MyClass:
    class_variable = "클래스 변수"

    def __init__(self, value):
        self.instance_variable = value

    # 인스턴스 메서드
    def instance_method(self):
        """self를 통해 인스턴스에 접근"""
        return f"인스턴스: {self.instance_variable}"

    # 클래스 메서드
    @classmethod
    def class_method(cls):
        """cls를 통해 클래스에 접근"""
        return f"클래스: {cls.class_variable}"

    # 정적 메서드
    @staticmethod
    def static_method(x, y):
        """self도 cls도 없음 - 독립적인 함수"""
        return x + y

# 사용
obj = MyClass("")

print(obj.instance_method())      # 인스턴스: 값
print(MyClass.class_method())     # 클래스: 클래스 변수
print(MyClass.static_method(5, 3))  # 8

언제 정적 메서드를 사용할까?

유틸리티 함수를 클래스에 묶어둘 때 사용합니다.

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
class MathUtils:
    """수학 유틸리티 클래스"""

    @staticmethod
    def is_even(n):
        """짝수 판별"""
        return n % 2 == 0

    @staticmethod
    def is_prime(n):
        """소수 판별"""
        if n < 2:
            return False
        for i in range(2, int(n ** 0.5) + 1):
            if n % i == 0:
                return False
        return True

    @staticmethod
    def factorial(n):
        """팩토리얼 계산"""
        if n <= 1:
            return 1
        result = 1
        for i in range(2, n + 1):
            result *= i
        return result

# 인스턴스 생성 없이 사용
print(MathUtils.is_even(10))     # True
print(MathUtils.is_prime(17))    # True
print(MathUtils.factorial(5))    # 120

실전 예제: 날짜 유틸리티

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
45
46
47
48
49
50
51
52
from datetime import datetime, timedelta

class DateUtils:
    """날짜 관련 유틸리티 클래스"""

    @staticmethod
    def is_weekend(date):
        """주말 여부 확인"""
        # weekday(): 월(0) ~ 일(6)
        return date.weekday() >= 5

    @staticmethod
    def add_business_days(date, days):
        """영업일 기준으로 날짜 더하기"""
        current = date
        added = 0

        while added < days:
            current += timedelta(days=1)
            if not DateUtils.is_weekend(current):
                added += 1

        return current

    @staticmethod
    def format_date(date, format_type="default"):
        """날짜 포맷팅"""
        formats = {
            "default": "%Y-%m-%d",
            "korean": "%Y년 %m월 %d일",
            "american": "%m/%d/%Y",
            "full": "%Y년 %m월 %d일 (%A)"
        }
        return date.strftime(formats.get(format_type, formats["default"]))

    @staticmethod
    def days_between(date1, date2):
        """두 날짜 사이의 일수"""
        delta = date2 - date1
        return abs(delta.days)

# 사용
today = datetime(2025, 4, 3)  # 목요일

print(f"오늘은 주말? {DateUtils.is_weekend(today)}")

next_business_day = DateUtils.add_business_days(today, 5)
print(f"5 영업일 후: {DateUtils.format_date(next_business_day, 'korean')}")

date1 = datetime(2025, 1, 1)
date2 = datetime(2025, 12, 31)
print(f"2025년은 {DateUtils.days_between(date1, date2)}")

실행 결과:

1
2
3
오늘은 주말? False
5 영업일 후: 2025년 04월 10일
2025년은 364일

🎯 학습 목표 4: 세 가지 메서드 타입의 차이점 알기

실전 예제: 완전한 클래스 설계

도서 관리 시스템

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
class Book:
    """도서를 관리하는 클래스"""

    # 클래스 변수
    total_books = 0
    categories = ["소설", "과학", "역사", "기술", "자기계발"]

    def __init__(self, title, author, isbn, category, price):
        """생성자"""
        self.title = title
        self.author = author
        self.isbn = isbn
        self.category = category
        self.price = price
        Book.total_books += 1

    # 인스턴스 메서드
    def get_info(self):
        """도서 정보 반환"""
        return f"{self.title} ({self.author})"

    def apply_discount(self, rate):
        """할인 적용"""
        discount = self.price * (rate / 100)
        return self.price - discount

    # 클래스 메서드
    @classmethod
    def get_total_books(cls):
        """총 도서 수 반환"""
        return cls.total_books

    @classmethod
    def from_string(cls, book_string):
        """팩토리 메서드: 문자열로 생성"""
        # 형식: "제목|저자|ISBN|카테고리|가격"
        parts = book_string.split('|')
        return cls(
            title=parts[0],
            author=parts[1],
            isbn=parts[2],
            category=parts[3],
            price=int(parts[4])
        )

    @classmethod
    def add_category(cls, category):
        """카테고리 추가"""
        if category not in cls.categories:
            cls.categories.append(category)
            print(f"'{category}' 카테고리가 추가되었습니다.")
        else:
            print(f"'{category}' 카테고리는 이미 존재합니다.")

    # 정적 메서드
    @staticmethod
    def validate_isbn(isbn):
        """ISBN 유효성 검사"""
        # 간단한 검사: 13자리 숫자
        return isbn.isdigit() and len(isbn) == 13

    @staticmethod
    def calculate_bulk_discount(price, quantity):
        """대량 구매 할인 계산"""
        if quantity >= 10:
            return price * 0.8  # 20% 할인
        elif quantity >= 5:
            return price * 0.9  # 10% 할인
        else:
            return price

    def __str__(self):
        """문자열 표현"""
        return f"[{self.category}] {self.title} - {self.author} ({self.price:,}원)"

# 사용 예시
print("="*50)
print("도서 관리 시스템")
print("="*50 + "\n")

# 일반 생성자
book1 = Book("파이썬 정복", "홍길동", "9781234567890", "기술", 35000)
print(book1)

# 팩토리 메서드
book2 = Book.from_string("클린 코드|로버트 마틴|9789876543210|기술|33000")
print(book2)

book3 = Book("해리 포터", "J.K. 롤링", "9781111111111", "소설", 25000)
print(book3)

print(f"\n{Book.get_total_books()}권 등록됨\n")

# 정적 메서드 사용
isbn = "9781234567890"
if Book.validate_isbn(isbn):
    print(f"{isbn}는 유효한 ISBN입니다.")

# 대량 구매 할인
print(f"\n5권 구매 시: {Book.calculate_bulk_discount(35000, 5):,}")
print(f"10권 구매 시: {Book.calculate_bulk_discount(35000, 10):,}")

# 카테고리 관리
print(f"\n현재 카테고리: {Book.categories}")
Book.add_category("만화")
print(f"업데이트된 카테고리: {Book.categories}")

실행 결과:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
==================================================
도서 관리 시스템
==================================================

[기술] 파이썬 정복 - 홍길동 (35,000원)
[기술] 클린 코드 - 로버트 마틴 (33,000원)
[소설] 해리 포터 - J.K. 롤링 (25,000원)

총 3권 등록됨

✅ 9781234567890는 유효한 ISBN입니다.

5권 구매 시: 31,500원
10권 구매 시: 28,000원

현재 카테고리: ['소설', '과학', '역사', '기술', '자기계발']
✅ '만화' 카테고리가 추가되었습니다.
업데이트된 카테고리: ['소설', '과학', '역사', '기술', '자기계발', '만화']

💡 실전 팁 & 주의사항

Tip 1: 클래스 변수는 클래스로 직접 변경하기

인스턴스를 통해 클래스 변수를 변경하면 새로운 인스턴스 변수가 생성되므로, 항상 클래스 이름으로 직접 변경하세요.

1
2
3
4
5
# ❌ 잘못된 방법
obj.class_var = "변경"  # 인스턴스 변수 생성

# ✅ 올바른 방법
ClassName.class_var = "변경"  # 클래스 변수 변경

Tip 2: 가변 객체를 클래스 변수로 사용하지 않기

리스트나 딕셔너리 같은 가변 객체를 클래스 변수로 사용하면 모든 인스턴스가 같은 객체를 공유하게 되므로 주의하세요.

1
2
3
4
5
6
7
8
# ❌ 위험한 패턴
class BadExample:
    items = []  # 모든 인스턴스가 공유

# ✅ 안전한 패턴
class GoodExample:
    def __init__(self):
        self.items = []  # 각 인스턴스마다 독립적

Tip 3: 팩토리 메서드로 유연한 객체 생성

클래스 메서드를 활용하면 다양한 방식으로 객체를 생성할 수 있어 코드가 더 유연해집니다.

1
2
3
4
5
@classmethod
def from_string(cls, data_string):
    """문자열로부터 객체 생성"""
    parts = data_string.split('|')
    return cls(parts[0], parts[1])

Tip 4: 정적 메서드는 네임스페이스 역할

관련된 유틸리티 함수들을 클래스로 묶어두면 코드 구조가 명확해지고 관리가 쉬워집니다.

1
2
3
4
5
6
7
8
class Utils:
    @staticmethod
    def validate_email(email):
        return '@' in email

    @staticmethod
    def format_phone(phone):
        return phone.replace('-', '')

🧪 연습 문제

문제 1: 학생 관리 시스템

다음 요구사항을 만족하는 Student 클래스를 작성하세요:

요구사항:

  1. 클래스 변수로 총 학생 수, 학교 이름 관리
  2. 인스턴스 메서드: 성적 추가, 평균 계산
  3. 클래스 메서드: 총 학생 수 반환, 학교 이름 변경
  4. 정적 메서드: 학점 계산 (A/B/C/D/F)
1
2
3
4
5
6
7
8
9
10
11
12
# 사용 예시
Student.set_school("파이썬 고등학교")

s1 = Student("홍길동", "2024001")
s1.add_score("수학", 95)
s1.add_score("영어", 88)

s2 = Student("김철수", "2024002")
s2.add_score("수학", 78)

print(f"총 학생 수: {Student.get_student_count()}")
print(f"학점: {Student.calculate_grade(92)}")
💡 힌트
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
class Student:
    school_name = ""
    student_count = 0

    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id
        self.scores = {}
        Student.student_count += 1

    def add_score(self, subject, score):
        self.scores[subject] = score

    def get_average(self):
        if not self.scores:
            return 0
        return sum(self.scores.values()) / len(self.scores)

    @classmethod
    def get_student_count(cls):
        return cls.student_count

    @classmethod
    def set_school(cls, name):
        cls.school_name = name

    @staticmethod
    def calculate_grade(score):
        if score >= 90:
            return 'A'
        elif score >= 80:
            return 'B'
        elif score >= 70:
            return 'C'
        elif score >= 60:
            return 'D'
        else:
            return 'F'
✅ 정답
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
class Student:
    """학생 정보를 관리하는 클래스"""

    school_name = ""
    student_count = 0

    def __init__(self, name, student_id):
        """생성자"""
        self.name = name
        self.student_id = student_id
        self.scores = {}
        Student.student_count += 1

    # 인스턴스 메서드
    def add_score(self, subject, score):
        """성적 추가"""
        self.scores[subject] = score
        print(f"{self.name} - {subject}: {score}")

    def get_average(self):
        """평균 계산"""
        if not self.scores:
            return 0
        return sum(self.scores.values()) / len(self.scores)

    def print_report(self):
        """성적표 출력"""
        print(f"\n{'='*40}")
        print(f"학교: {Student.school_name}")
        print(f"학생: {self.name} ({self.student_id})")
        print(f"{'-'*40}")
        for subject, score in self.scores.items():
            grade = Student.calculate_grade(score)
            print(f"{subject}: {score}점 ({grade})")
        print(f"{'-'*40}")
        avg = self.get_average()
        print(f"평균: {avg:.2f}점 ({Student.calculate_grade(avg)})")
        print(f"{'='*40}\n")

    # 클래스 메서드
    @classmethod
    def get_student_count(cls):
        """총 학생 수 반환"""
        return cls.student_count

    @classmethod
    def set_school(cls, name):
        """학교 이름 설정"""
        cls.school_name = name
        print(f"🏫 학교 이름: {name}")

    # 정적 메서드
    @staticmethod
    def calculate_grade(score):
        """학점 계산"""
        if score >= 90:
            return 'A'
        elif score >= 80:
            return 'B'
        elif score >= 70:
            return 'C'
        elif score >= 60:
            return 'D'
        else:
            return 'F'

# 테스트
Student.set_school("파이썬 고등학교")

s1 = Student("홍길동", "2024001")
s1.add_score("수학", 95)
s1.add_score("영어", 88)
s1.add_score("과학", 92)

s2 = Student("김철수", "2024002")
s2.add_score("수학", 78)
s2.add_score("영어", 85)

print(f"\n총 학생 수: {Student.get_student_count()}\n")

s1.print_report()
s2.print_report()

print(f"학점 예시: {Student.calculate_grade(92)}")

문제 2: 시간 변환 유틸리티

시간 변환 기능을 제공하는 TimeConverter 클래스를 작성하세요:

요구사항:

  1. 정적 메서드만 사용 (인스턴스 생성 불필요)
  2. 초 → 시:분:초 변환
  3. 시:분:초 → 초 변환
  4. 시간 포맷팅
1
2
3
4
# 사용 예시
print(TimeConverter.seconds_to_hms(3665))  # "1:01:05"
print(TimeConverter.hms_to_seconds("1:01:05"))  # 3665
print(TimeConverter.format_time(3665))  # "1시간 1분 5초"
✅ 정답
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
45
46
47
48
49
50
51
class TimeConverter:
    """시간 변환 유틸리티 클래스"""

    @staticmethod
    def seconds_to_hms(seconds):
        """초를 시:분:초 형식으로 변환"""
        hours = seconds // 3600
        minutes = (seconds % 3600) // 60
        secs = seconds % 60
        return f"{hours}:{minutes:02d}:{secs:02d}"

    @staticmethod
    def hms_to_seconds(hms_string):
        """시:분:초 형식을 초로 변환"""
        parts = hms_string.split(':')
        hours = int(parts[0])
        minutes = int(parts[1])
        secs = int(parts[2])
        return hours * 3600 + minutes * 60 + secs

    @staticmethod
    def format_time(seconds):
        """초를 읽기 쉬운 형식으로 변환"""
        hours = seconds // 3600
        minutes = (seconds % 3600) // 60
        secs = seconds % 60

        parts = []
        if hours > 0:
            parts.append(f"{hours}시간")
        if minutes > 0:
            parts.append(f"{minutes}")
        if secs > 0 or not parts:
            parts.append(f"{secs}")

        return ' '.join(parts)

    @staticmethod
    def add_times(time1, time2):
        """두 시간 더하기 (시:분:초 형식)"""
        seconds1 = TimeConverter.hms_to_seconds(time1)
        seconds2 = TimeConverter.hms_to_seconds(time2)
        total = seconds1 + seconds2
        return TimeConverter.seconds_to_hms(total)

# 테스트
print(TimeConverter.seconds_to_hms(3665))
print(TimeConverter.hms_to_seconds("1:01:05"))
print(TimeConverter.format_time(3665))
print(TimeConverter.format_time(65))
print(TimeConverter.add_times("1:30:45", "2:45:30"))

실행 결과:

1
2
3
4
5
1:01:05
3665
1시간 1분 5초
1분 5초
4:16:15

📝 오늘 배운 내용 정리

메서드 종류 첫 번째 매개변수 접근 가능 사용 목적
인스턴스 메서드 self 인스턴스 변수 개별 객체 동작
클래스 메서드 cls 클래스 변수 클래스 수준 작업, 팩토리
정적 메서드 없음 둘 다 불가 독립적인 유틸리티

언제 무엇을 사용할까?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Example:
    class_var = 0

    def __init__(self, value):
        self.instance_var = value

    # ✅ 인스턴스 메서드: 인스턴스 데이터 필요
    def instance_method(self):
        return self.instance_var

    # ✅ 클래스 메서드: 클래스 데이터 필요 또는 팩토리
    @classmethod
    def class_method(cls):
        return cls.class_var

    # ✅ 정적 메서드: 둘 다 필요 없는 독립 함수
    @staticmethod
    def static_method(x, y):
        return x + y

🔗 관련 자료

📚 이전 학습

Day 33: 인스턴스 변수와 메서드 ⭐⭐⭐

어제는 인스턴스 변수와 메서드, Property 데코레이터를 활용한 안전한 속성 관리 방법을 배웠습니다!

📚 다음 학습

Day 35: 상속의 기초 ⭐⭐⭐

내일은 상속(Inheritance)의 개념과 필요성, 부모 클래스와 자식 클래스 관계, super() 함수 사용법, 메서드 오버라이딩 기초를 배웁니다!


“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀

Day 34/100 Phase 4: 객체지향 프로그래밍 #100DaysOfPython
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.