[Python 100일 챌린지] Day 33 - 인스턴스 변수와 메서드
객체에 데이터만 저장하면 되나요? 그럼 딕셔너리랑 뭐가 다를까요? 🤔 ──진짜 차이는 “행동(메서드)”을 가질 수 있다는 점입니다! 😊
게임 캐릭터를 생각해보세요. HP, 공격력 같은 속성만 있으면 아무것도 못 합니다.
attack(),defend(),heal()같은 행동이 있어야 진짜 캐릭터죠!자동차도 마찬가지입니다. 색상, 속도 같은 데이터만 있으면 주차장에 세워진 차와 같습니다.
drive(),stop(),accelerate()같은 메서드가 있어야 움직이는 차가 됩니다!오늘은 객체에 “생명”을 불어넣는 인스턴스 메서드를 배웁니다! 💡
🎯 오늘의 학습 목표
⭐⭐⭐ (35-45분 완독)
📚 사전 지식
🎯 학습 목표 1: 인스턴스 메서드의 개념 이해하기
인스턴스 변수 vs 인스턴스 메서드
인스턴스 변수 (Instance Variable)
각 객체가 독립적으로 가지는 데이터입니다.
1
2
3
4
5
6
7
8
9
10
class Student:
def __init__(self, name, age):
self.name = name # 인스턴스 변수
self.age = age # 인스턴스 변수
student1 = Student("홍길동", 20)
student2 = Student("김철수", 22)
print(student1.name, student1.age) # 홍길동 20
print(student2.name, student2.age) # 김철수 22
인스턴스 메서드 (Instance Method)
각 객체가 수행할 수 있는 동작입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self): # 인스턴스 메서드
return f"안녕하세요, 저는 {self.name}이고 {self.age}살입니다."
def is_adult(self): # 인스턴스 메서드
return self.age >= 20
student = Student("홍길동", 20)
print(student.introduce()) # 안녕하세요, 저는 홍길동이고 20살입니다.
print(student.is_adult()) # True
🎯 학습 목표 2: self 매개변수의 역할 알기
Private 변수와 Name Mangling
Python에서 진정한 private은 없지만, 네이밍 규칙으로 접근을 제한할 수 있습니다.
1. Public 변수 (기본)
누구나 접근 가능한 변수입니다.
1
2
3
4
5
6
7
8
class BankAccount:
def __init__(self, balance):
self.balance = balance # Public 변수
account = BankAccount(10000)
print(account.balance) # 10000 (직접 접근 가능)
account.balance = -5000 # ❌ 음수로 변경 가능! (위험)
print(account.balance) # -5000
2. Protected 변수 (언더스코어 1개: _variable)
“외부에서 직접 접근하지 말아주세요”라는 약속입니다.
1
2
3
4
5
6
class BankAccount:
def __init__(self, balance):
self._balance = balance # Protected 변수
account = BankAccount(10000)
print(account._balance) # 10000 (기술적으로는 가능하지만 권장하지 않음)
💡 관례: _로 시작하는 변수는 “내부용”이라는 신호입니다.
3. Private 변수 (언더스코어 2개: __variable)
Name Mangling으로 접근을 어렵게 만듭니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class BankAccount:
def __init__(self, balance):
self.__balance = balance # Private 변수
def get_balance(self):
return self.__balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
account = BankAccount(10000)
print(account.get_balance()) # 10000 (메서드로 접근)
# 직접 접근 시도
print(account.__balance) # AttributeError!
실행 결과:
1
2
3
4
5
10000
Traceback (most recent call last):
File "...", line X, in <module>
print(account.__balance)
AttributeError: 'BankAccount' object has no attribute '__balance'
Name Mangling 동작 원리
Python은 __변수명을 _클래스명__변수명으로 변환합니다.
1
2
3
4
5
6
7
8
9
10
11
12
class BankAccount:
def __init__(self, balance):
self.__balance = balance
account = BankAccount(10000)
# 실제 변수명 확인
print(dir(account))
# [..., '_BankAccount__balance', ...]
# 변환된 이름으로 접근 (권장하지 않음!)
print(account._BankAccount__balance) # 10000
💡 하지만 이렇게 접근하지 마세요! Private의 의도를 무시하는 행동입니다.
🎯 학습 목표 3: 인스턴스 메서드 정의하고 호출하기
Getter와 Setter 메서드
Private 변수에 안전하게 접근하기 위한 패턴입니다.
전통적인 방식
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 BankAccount:
def __init__(self, owner, balance):
self.__owner = owner
self.__balance = balance
# Getter 메서드
def get_balance(self):
"""잔액 조회"""
return self.__balance
def get_owner(self):
"""예금주 조회"""
return self.__owner
# Setter 메서드
def set_balance(self, balance):
"""잔액 설정 (유효성 검사 포함)"""
if balance < 0:
print("❌ 잔액은 음수가 될 수 없습니다.")
return
self.__balance = balance
def deposit(self, amount):
"""입금"""
if amount <= 0:
return "❌ 입금액은 0보다 커야 합니다."
self.__balance += amount
return f"✅ {amount:,}원 입금 완료 (잔액: {self.__balance:,}원)"
def withdraw(self, amount):
"""출금"""
if amount <= 0:
return "❌ 출금액은 0보다 커야 합니다."
if amount > self.__balance:
return f"❌ 잔액 부족 (현재 잔액: {self.__balance:,}원)"
self.__balance -= amount
return f"✅ {amount:,}원 출금 완료 (잔액: {self.__balance:,}원)"
# 사용
account = BankAccount("홍길동", 10000)
print(account.get_owner()) # 홍길동
print(account.get_balance()) # 10000
print(account.deposit(5000)) # ✅ 5,000원 입금 완료
print(account.withdraw(3000)) # ✅ 3,000원 출금 완료
# 직접 수정 시도 (불가능)
# account.__balance = -1000 # AttributeError!
# Setter로 음수 방지
account.set_balance(-5000) # ❌ 잔액은 음수가 될 수 없습니다.
실행 결과:
1
2
3
4
5
홍길동
10000
✅ 5,000원 입금 완료 (잔액: 15,000원)
✅ 3,000원 출금 완료 (잔액: 12,000원)
❌ 잔액은 음수가 될 수 없습니다.
⭐ @property 데코레이터
Python의 @property를 사용하면 메서드를 속성처럼 사용할 수 있습니다!
기본 문법
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
class Person:
def __init__(self, name, age):
self.__name = name
self.__age = age
@property
def name(self):
"""Getter: 이름 조회"""
return self.__name
@property
def age(self):
"""Getter: 나이 조회"""
return self.__age
@age.setter
def age(self, value):
"""Setter: 나이 설정 (유효성 검사)"""
if value < 0:
print("❌ 나이는 음수가 될 수 없습니다.")
return
if value > 150:
print("❌ 나이가 너무 많습니다.")
return
self.__age = value
# 사용 - 메서드가 아닌 속성처럼!
person = Person("홍길동", 30)
# Getter (괄호 없이!)
print(person.name) # 홍길동
print(person.age) # 30
# Setter (= 사용!)
person.age = 31
print(person.age) # 31
person.age = -5 # ❌ 나이는 음수가 될 수 없습니다.
person.age = 200 # ❌ 나이가 너무 많습니다.
실행 결과:
1
2
3
4
5
홍길동
30
31
❌ 나이는 음수가 될 수 없습니다.
❌ 나이가 너무 많습니다.
Before & After 비교
Before (전통적 방식)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BankAccount:
def __init__(self, balance):
self.__balance = balance
def get_balance(self):
return self.__balance
def set_balance(self, value):
if value >= 0:
self.__balance = value
account = BankAccount(10000)
print(account.get_balance()) # 메서드 호출
account.set_balance(20000) # 메서드 호출
After (@property 사용) ✅
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class BankAccount:
def __init__(self, balance):
self.__balance = balance
@property
def balance(self):
return self.__balance
@balance.setter
def balance(self, value):
if value >= 0:
self.__balance = value
account = BankAccount(10000)
print(account.balance) # 속성 접근!
account.balance = 20000 # 속성 할당!
🎯 학습 목표 4: 메서드로 객체 상태 변경하기
실전 예제
예제 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
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
class Temperature:
"""온도를 관리하는 클래스 (자동 변환)"""
def __init__(self, celsius=0):
"""생성자: 섭씨 온도 초기화"""
self.__celsius = celsius
@property
def celsius(self):
"""Getter: 섭씨 온도"""
return self.__celsius
@celsius.setter
def celsius(self, value):
"""Setter: 섭씨 온도 (절대영도 체크)"""
if value < -273.15:
print("❌ 절대영도(-273.15°C) 이하는 불가능합니다.")
return
self.__celsius = value
@property
def fahrenheit(self):
"""Getter: 화씨 온도 (자동 계산)"""
return self.__celsius * 9/5 + 32
@fahrenheit.setter
def fahrenheit(self, value):
"""Setter: 화씨 온도 (섭씨로 변환 저장)"""
celsius = (value - 32) * 5/9
if celsius < -273.15:
print("❌ 절대영도 이하는 불가능합니다.")
return
self.__celsius = celsius
@property
def kelvin(self):
"""Getter: 켈빈 온도 (자동 계산)"""
return self.__celsius + 273.15
@kelvin.setter
def kelvin(self, value):
"""Setter: 켈빈 온도 (섭씨로 변환 저장)"""
if value < 0:
print("❌ 켈빈 온도는 0 이상이어야 합니다.")
return
self.__celsius = value - 273.15
def print_all(self):
"""모든 온도 출력"""
print(f"{'='*40}")
print(f"섭씨: {self.celsius:.2f}°C")
print(f"화씨: {self.fahrenheit:.2f}°F")
print(f"켈빈: {self.kelvin:.2f}K")
print(f"{'='*40}\n")
# 사용
temp = Temperature(25)
temp.print_all()
# 화씨로 설정하면 섭씨도 자동 변환!
temp.fahrenheit = 98.6
temp.print_all()
# 켈빈으로 설정
temp.kelvin = 300
temp.print_all()
# 유효성 검사
temp.celsius = -300 # ❌ 절대영도 이하는 불가능합니다.
실행 결과:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
========================================
섭씨: 25.00°C
화씨: 77.00°F
켈빈: 298.15K
========================================
========================================
섭씨: 37.00°C
화씨: 98.60°F
켈빈: 310.15K
========================================
========================================
섭씨: 26.85°C
화씨: 80.33°F
켈빈: 300.00K
========================================
❌ 절대영도(-273.15°C) 이하는 불가능합니다.
예제 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
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
class Rectangle:
"""사각형을 표현하는 클래스"""
def __init__(self, width, height):
"""생성자: 가로, 세로 초기화"""
self.__width = width
self.__height = height
@property
def width(self):
"""Getter: 가로"""
return self.__width
@width.setter
def width(self, value):
"""Setter: 가로 (양수 체크)"""
if value <= 0:
print("❌ 가로 길이는 0보다 커야 합니다.")
return
self.__width = value
@property
def height(self):
"""Getter: 세로"""
return self.__height
@height.setter
def height(self, value):
"""Setter: 세로 (양수 체크)"""
if value <= 0:
print("❌ 세로 길이는 0보다 커야 합니다.")
return
self.__height = value
@property
def area(self):
"""Getter: 넓이 (자동 계산, read-only)"""
return self.__width * self.__height
@property
def perimeter(self):
"""Getter: 둘레 (자동 계산, read-only)"""
return 2 * (self.__width + self.__height)
def print_info(self):
"""사각형 정보 출력"""
print(f"{'='*40}")
print(f"가로: {self.width}")
print(f"세로: {self.height}")
print(f"넓이: {self.area}")
print(f"둘레: {self.perimeter}")
print(f"{'='*40}\n")
# 사용
rect = Rectangle(5, 3)
rect.print_info()
# 가로 변경 - 넓이/둘레 자동 업데이트!
rect.width = 10
rect.print_info()
# read-only 속성 변경 시도
try:
rect.area = 100 # AttributeError!
except AttributeError as e:
print(f"❌ 에러: {e}\n")
# 유효성 검사
rect.width = -5 # ❌ 가로 길이는 0보다 커야 합니다.
실행 결과:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
========================================
가로: 5
세로: 3
넓이: 15
둘레: 16
========================================
========================================
가로: 10
세로: 3
넓이: 30
둘레: 26
========================================
❌ 에러: can't set attribute
❌ 가로 길이는 0보다 커야 합니다.
예제 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
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
class Employee:
"""직원 정보를 관리하는 클래스"""
def __init__(self, name, monthly_salary):
"""생성자: 이름, 월급 초기화"""
self.__name = name
self.__monthly_salary = monthly_salary
@property
def name(self):
"""Getter: 이름 (read-only)"""
return self.__name
@property
def monthly_salary(self):
"""Getter: 월급"""
return self.__monthly_salary
@monthly_salary.setter
def monthly_salary(self, value):
"""Setter: 월급 (양수 체크)"""
if value <= 0:
print("❌ 월급은 0보다 커야 합니다.")
return
self.__monthly_salary = value
print(f"✅ {self.__name}님의 월급이 {value:,}원으로 변경되었습니다.")
@property
def annual_salary(self):
"""Getter: 연봉 (자동 계산)"""
return self.__monthly_salary * 12
@property
def weekly_salary(self):
"""Getter: 주급 (자동 계산)"""
return self.__monthly_salary // 4
def raise_salary(self, rate):
"""월급 인상 (퍼센트)"""
if rate <= 0:
print("❌ 인상률은 0보다 커야 합니다.")
return
old_salary = self.__monthly_salary
self.__monthly_salary = int(self.__monthly_salary * (1 + rate / 100))
increase = self.__monthly_salary - old_salary
print(f"💰 {self.__name}님의 월급이 {rate}% 인상되었습니다!")
print(f" 이전: {old_salary:,}원")
print(f" 현재: {self.__monthly_salary:,}원")
print(f" 인상액: {increase:,}원")
def print_info(self):
"""직원 정보 출력"""
print(f"\n{'='*50}")
print(f"이름: {self.name}")
print(f"{'-'*50}")
print(f"월급: {self.monthly_salary:,}원")
print(f"주급: {self.weekly_salary:,}원")
print(f"연봉: {self.annual_salary:,}원")
print(f"{'='*50}\n")
# 사용
emp = Employee("홍길동", 3000000)
emp.print_info()
# 월급 인상
emp.raise_salary(10)
emp.print_info()
# 월급 직접 변경 (setter 호출)
emp.monthly_salary = 3500000
emp.print_info()
# 이름 변경 시도 (read-only)
try:
emp.name = "김철수" # AttributeError!
except AttributeError as e:
print(f"❌ 에러: {e}")
실행 결과:
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
==================================================
이름: 홍길동
--------------------------------------------------
월급: 3,000,000원
주급: 750,000원
연봉: 36,000,000원
==================================================
💰 홍길동님의 월급이 10% 인상되었습니다!
이전: 3,000,000원
현재: 3,300,000원
인상액: 300,000원
==================================================
이름: 홍길동
--------------------------------------------------
월급: 3,300,000원
주급: 825,000원
연봉: 39,600,000원
==================================================
✅ 홍길동님의 월급이 3,500,000원으로 변경되었습니다.
==================================================
이름: 홍길동
--------------------------------------------------
월급: 3,500,000원
주급: 875,000원
연봉: 42,000,000원
==================================================
❌ 에러: can't set attribute
📊 캡슐화와 정보 은닉
캡슐화(Encapsulation)는 데이터와 메서드를 하나로 묶고, 외부 접근을 제한하는 개념입니다.
캡슐화의 장점
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
class Password:
"""비밀번호를 안전하게 관리하는 클래스"""
def __init__(self, password):
"""생성자: 비밀번호 초기화"""
self.__password = self.__hash_password(password)
def __hash_password(self, password):
"""Private 메서드: 비밀번호 해싱 (간단한 예시)"""
# 실제로는 hashlib.sha256 등 사용
return f"hashed_{password}"
def check_password(self, input_password):
"""비밀번호 확인"""
hashed = self.__hash_password(input_password)
return hashed == self.__password
def change_password(self, old_password, new_password):
"""비밀번호 변경"""
if not self.check_password(old_password):
return "❌ 현재 비밀번호가 일치하지 않습니다."
if len(new_password) < 8:
return "❌ 새 비밀번호는 8자 이상이어야 합니다."
self.__password = self.__hash_password(new_password)
return "✅ 비밀번호가 변경되었습니다."
# 사용
pwd = Password("mysecret123")
# 비밀번호 확인
print(pwd.check_password("mysecret123")) # True
print(pwd.check_password("wrong")) # False
# 비밀번호 변경
print(pwd.change_password("wrong", "newpass123")) # ❌ 현재 비밀번호 불일치
print(pwd.change_password("mysecret123", "short")) # ❌ 8자 미만
print(pwd.change_password("mysecret123", "newpass123")) # ✅ 변경 성공
# 직접 접근 불가 (보안!)
# print(pwd.__password) # AttributeError!
실행 결과:
1
2
3
4
5
True
False
❌ 현재 비밀번호가 일치하지 않습니다.
❌ 새 비밀번호는 8자 이상이어야 합니다.
✅ 비밀번호가 변경되었습니다.
💡 실전 팁 & 주의사항
Tip 1: Private 변수는 진짜 Private이 아님
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class SecretData:
def __init__(self, secret):
self.__secret = secret # "Private" 변수
data = SecretData("비밀")
# ❌ 직접 접근 불가
# print(data.__secret) # AttributeError
# ⚠️ 하지만 Name Mangling으로 접근 가능 (권장하지 않음!)
print(data._SecretData__secret) # 비밀
# ✅ 권장: Getter 메서드 제공
class SecretData:
def __init__(self, secret):
self.__secret = secret
@property
def secret(self):
return self.__secret
Tip 2: Setter에서 유효성 검사 필수
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
# ❌ 나쁜 예 - 유효성 검사 없음
class Person:
def __init__(self, age):
self.age = age # 음수 입력 가능!
person = Person(-5) # 문제 발생
# ✅ 좋은 예 - 유효성 검사
class Person:
def __init__(self, age):
self.__age = 0
self.age = age
@property
def age(self):
return self.__age
@age.setter
def age(self, value):
if value < 0:
raise ValueError("나이는 0 이상이어야 합니다.")
self.__age = value
try:
person = Person(-5) # ValueError 발생
except ValueError as e:
print(f"오류: {e}")
Tip 3: @property는 계산된 속성에 유용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Rectangle:
def __init__(self, width, height):
self.width = width
self.height = height
@property
def area(self):
"""면적 계산 (읽기 전용)"""
return self.width * self.height
@property
def perimeter(self):
"""둘레 계산 (읽기 전용)"""
return 2 * (self.width + self.height)
rect = Rectangle(10, 5)
print(rect.area) # 50 (메서드처럼 () 없이 접근)
print(rect.perimeter) # 30
# rect.area = 100 # AttributeError (setter 없음)
🧪 연습 문제
문제 1: 시간 클래스
시, 분, 초를 관리하는 Time 클래스를 작성하세요:
요구사항:
__init__(self, hour=0, minute=0, second=0)생성자@property로 hour, minute, second Getter/Setter 구현- 유효성 검사 (hour: 0-23, minute/second: 0-59)
total_seconds속성 (읽기 전용, 총 초 계산)add_seconds(n)메서드 (n초 추가, 자동 시간 조정)
1
2
3
4
5
6
7
8
# 사용 예시
time = Time(10, 30, 45)
print(time.hour, time.minute, time.second) # 10 30 45
print(time.total_seconds) # 37845
time.minute = 75 # ❌ 유효성 검사 실패
time.add_seconds(100)
print(time.hour, time.minute, time.second) # 10 32 25
💡 힌트
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 Time:
def __init__(self, hour=0, minute=0, second=0):
self.__hour = 0
self.__minute = 0
self.__second = 0
# setter 호출로 유효성 검사
self.hour = hour
self.minute = minute
self.second = second
@property
def hour(self):
return self.__hour
@hour.setter
def hour(self, value):
if 0 <= value <= 23:
self.__hour = value
else:
print("❌ hour는 0-23 사이여야 합니다.")
@property
def total_seconds(self):
return self.__hour * 3600 + self.__minute * 60 + self.__second
def add_seconds(self, n):
total = self.total_seconds + n
# 시, 분, 초로 변환
pass
✅ 정답
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
class Time:
"""시간을 관리하는 클래스"""
def __init__(self, hour=0, minute=0, second=0):
"""생성자"""
self.__hour = 0
self.__minute = 0
self.__second = 0
self.hour = hour
self.minute = minute
self.second = second
@property
def hour(self):
return self.__hour
@hour.setter
def hour(self, value):
if 0 <= value <= 23:
self.__hour = value
else:
print("❌ hour는 0-23 사이여야 합니다.")
@property
def minute(self):
return self.__minute
@minute.setter
def minute(self, value):
if 0 <= value <= 59:
self.__minute = value
else:
print("❌ minute는 0-59 사이여야 합니다.")
@property
def second(self):
return self.__second
@second.setter
def second(self, value):
if 0 <= value <= 59:
self.__second = value
else:
print("❌ second는 0-59 사이여야 합니다.")
@property
def total_seconds(self):
"""총 초 계산 (읽기 전용)"""
return self.__hour * 3600 + self.__minute * 60 + self.__second
def add_seconds(self, n):
"""n초 추가"""
total = self.total_seconds + n
# 24시간 넘으면 다음 날로
total = total % (24 * 3600)
self.__hour = total // 3600
self.__minute = (total % 3600) // 60
self.__second = total % 60
def __str__(self):
return f"{self.__hour:02d}:{self.__minute:02d}:{self.__second:02d}"
# 테스트
time = Time(10, 30, 45)
print(time) # 10:30:45
print(f"총 {time.total_seconds}초")
time.minute = 75 # ❌ minute는 0-59 사이여야 합니다.
time.add_seconds(100)
print(time) # 10:32:25
time.add_seconds(7200) # 2시간 추가
print(time) # 12:32:25
문제 2: 학생 성적 클래스
학생 성적을 관리하는 StudentGrade 클래스를 작성하세요:
요구사항:
- Private 변수로 이름, 수학, 영어, 과학 점수 저장
@property로 각 과목 점수 Getter/Setter (0-100 범위 체크)average속성 (읽기 전용, 평균 계산)grade속성 (읽기 전용, 등급 계산: A/B/C/D/F)
1
2
3
4
5
6
7
8
# 등급 기준: A(90~), B(80~), C(70~), D(60~), F(~59)
# 사용 예시
student = StudentGrade("홍길동", 95, 88, 92)
print(student.average) # 91.67
print(student.grade) # A
student.math = 150 # ❌ 유효성 검사 실패
✅ 정답
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
class StudentGrade:
"""학생 성적을 관리하는 클래스"""
def __init__(self, name, math, english, science):
"""생성자"""
self.__name = name
self.__math = 0
self.__english = 0
self.__science = 0
self.math = math
self.english = english
self.science = science
@property
def name(self):
return self.__name
@property
def math(self):
return self.__math
@math.setter
def math(self, value):
if 0 <= value <= 100:
self.__math = value
else:
print("❌ 점수는 0-100 사이여야 합니다.")
@property
def english(self):
return self.__english
@english.setter
def english(self, value):
if 0 <= value <= 100:
self.__english = value
else:
print("❌ 점수는 0-100 사이여야 합니다.")
@property
def science(self):
return self.__science
@science.setter
def science(self, value):
if 0 <= value <= 100:
self.__science = value
else:
print("❌ 점수는 0-100 사이여야 합니다.")
@property
def average(self):
"""평균 계산 (읽기 전용)"""
return (self.__math + self.__english + self.__science) / 3
@property
def grade(self):
"""등급 계산 (읽기 전용)"""
avg = self.average
if avg >= 90:
return 'A'
elif avg >= 80:
return 'B'
elif avg >= 70:
return 'C'
elif avg >= 60:
return 'D'
else:
return 'F'
def print_report(self):
"""성적표 출력"""
print(f"\n{'='*40}")
print(f"이름: {self.name}")
print(f"{'-'*40}")
print(f"수학: {self.math}점")
print(f"영어: {self.english}점")
print(f"과학: {self.science}점")
print(f"{'-'*40}")
print(f"평균: {self.average:.2f}점")
print(f"등급: {self.grade}")
print(f"{'='*40}\n")
# 테스트
student = StudentGrade("홍길동", 95, 88, 92)
student.print_report()
student.math = 150 # ❌ 점수는 0-100 사이여야 합니다.
student.math = 100
student.print_report()
📝 오늘 배운 내용 정리
| 개념 | 설명 | 예시 |
|---|---|---|
| Public 변수 | 누구나 접근 가능 | self.name |
| Protected 변수 | _로 시작, 내부용 신호 | self._balance |
| Private 변수 | __로 시작, Name Mangling | self.__password |
| @property | Getter 메서드를 속성처럼 | @property def name(self): |
| @속성.setter | Setter 메서드 | @name.setter def name(self, value): |
| 캡슐화 | 데이터 보호 및 접근 제어 | Private + Property |
@property 사용 패턴
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
class Example:
def __init__(self, value):
self.__value = value
@property
def value(self):
"""Getter"""
return self.__value
@value.setter
def value(self, new_value):
"""Setter (유효성 검사)"""
if new_value >= 0:
self.__value = new_value
else:
print("❌ 값은 0 이상이어야 합니다.")
@property
def doubled(self):
"""계산된 속성 (읽기 전용)"""
return self.__value * 2
# 사용
obj = Example(10)
print(obj.value) # 10 (Getter)
obj.value = 20 # Setter
print(obj.doubled) # 40 (계산됨)
🔗 관련 자료
📚 이전 학습
Day 32: 생성자와 소멸자 ⭐⭐⭐
어제는 __init__ 메서드로 객체를 초기화하고 __del__ 메서드로 객체를 정리하는 방법을 배웠습니다!
📚 다음 학습
Day 34: 클래스 메서드와 정적 메서드 ⭐⭐⭐
내일은 클래스 메서드와 정적 메서드를 배우고 다양한 메서드 활용법을 익힙니다!
“늦었다고 생각할 때가 가장 빠른 시기입니다!” 🚀
Day 33/100 Phase 4: 객체지향 프로그래밍 #100DaysOfPython
