6단원 과제 정답: Python 클래스 (Class)¶
문제 1. 클래스 메서드 호출 방식¶
① Hello, I'm Leo!
② Hello, I'm Mia!
해설
Greeter.greet(g) # 클래스 메서드처럼 명시적으로 self 전달
g.greet() # 인스턴스 메서드 방식 (파이썬이 자동으로 g를 self로 전달)
| 항목 | 호출 | 결과 | 이유 |
|---|---|---|---|
| ① | Greeter.greet(g) |
Hello, I'm Leo! |
self = g, g.name = "Leo" |
| ② | g2.greet() |
Hello, I'm Mia! |
self = g2, g2.name = "Mia" |
두 호출 방식은 완전히 동일합니다. g.greet()은 파이썬이 Greeter.greet(g)로 변환합니다.
문제 2. 인스턴스 변수는 독립적이다¶
① 0
② 0
③ 50
④ 50
⑤ False
해설
b1 = Box() → b1.width=0, b1.height=0
b2 = Box() → b2.width=0, b2.height=0
b1.width = 50 → b1.width=50 (b2는 변하지 않음)
b1.resize(10) → b1.height += 10 → b1.height=10 ... 아니, b1.height=0+0
잠깐, resize를 다시 봅시다:
def resize(self, amount):
self.height += amount
b1.resize(10) → b1.height = 0 + 10 = 10
| 항목 | 식 | 결과 | 이유 |
|---|---|---|---|
| ① | b1.width (초기) |
0 |
__init__에서 width=0 |
| ② | b2.width (초기) |
0 |
독립된 객체 |
| ③ | b1.width (수정 후) |
50 |
b1.width = 50 직접 수정 |
| ④ | b1.width (resize 후) |
50 |
resize는 height만 변경 |
| ⑤ | b1.width == b2.width |
False |
50 ≠ 0 |
문제 3. ⚠️ self.score += n 의 함정¶
① 0
② 10
③ 0
④ 10
해설 — 핵심 함정
class Player:
score = 0 # 클래스 변수
def add(self, n):
self.score += n # 이 줄이 함정!
self.score += n은 self.score = self.score + n으로 풀립니다.
첫 번째 호출 p1.add(10):
- 오른쪽
self.score→p1에 인스턴스 변수 없음 → 클래스 변수Player.score = 0읽음 0 + 10 = 10- 왼쪽 대입 →
p1.score = 10(인스턴스 변수 생성!) Player.score는 여전히0
| 항목 | 식 | 결과 | 이유 |
|---|---|---|---|
| ① | Player.score |
0 |
클래스 변수 — add() 호출해도 바뀌지 않음 |
| ② | p1.score |
10 |
p1에 인스턴스 변수 score=10이 새로 생김 |
| ③ | p2.score |
0 |
p2는 add() 호출 안 했으므로 클래스 변수 그대로 |
| ④ | p1.score (두 번째 후) |
10 |
p1.add(10) 재호출: 이번엔 인스턴스 변수 10에서 시작 → 20? |
주의: 두 번째 p1.add(10) 이후 p1.score는 20이 됩니다.
문제 4. ⚠️ 클래스 변수 리스트 함정¶
① ['Alice']
② ['Alice', 'Bob']
해설 — 공유 가변 객체
class Team:
members = [] # 모든 인스턴스가 공유하는 리스트!
members는 클래스 변수입니다. self.members.append(name)은 새 리스트를 만들지 않고 공유된 리스트를 수정합니다.
| 항목 | 결과 | 이유 |
|---|---|---|
| ① | ['Alice'] |
t1.add("Alice") → 공유 리스트에 추가 |
| ② | ['Alice', 'Bob'] |
t2.add("Bob") → 같은 리스트에 추가 |
올바른 방법:
def __init__(self):
self.members = [] # 인스턴스마다 별도 리스트 생성
문제 5. __str__ 특수 메서드¶
① <__main__.Point object at 0x...>
② (3, 4)
③ Point(3, 4)
해설
| 항목 | 식 | 결과 | 이유 |
|---|---|---|---|
| ① | print(p1) |
<...object...> |
__str__ 없음 → 기본 객체 표현 |
| ② | print(p2) |
(3, 4) |
__str__ 정의됨 → f"({self.x}, {self.y})" |
| ③ | repr(p2) |
Point(3, 4) |
__repr__ 정의됨 → f"Point({self.x}, {self.y})" |
__str__: print(), str() 호출 시 사용 (사람이 읽기 좋은 형식)
__repr__: repr(), 디버거 출력 시 사용 (개발자용, 재현 가능한 형식)
문제 6. 상속, super(), isinstance()¶
① Animal created: 동물
② Dog created: 바둑이
③ 동물
④ 바둑이
⑤ 멍!
⑥ True
⑦ True
⑧ False
해설
class Animal:
def __init__(self, name):
print(f"Animal created: {name}")
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # Animal.__init__ 먼저 실행
print(f"Dog created: {name}")
self.breed = breed
Dog("바둑이", "진돗개") 호출 시 순서:
1. super().__init__("바둑이") → Animal created: 바둑이 출력
2. 이후 Dog created: 바둑이 출력
| 항목 | 식 | 결과 | 이유 |
|---|---|---|---|
| ⑥ | isinstance(d, Dog) |
True |
d는 Dog의 인스턴스 |
| ⑦ | isinstance(d, Animal) |
True |
Dog가 Animal을 상속 → 부모 타입도 True |
| ⑧ | isinstance(a, Dog) |
False |
a는 Animal이지 Dog가 아님 |
문제 7. ⚠️ 이름 맹글링 (Name Mangling)¶
① True
② False
③ True
④ I have a secret.
해설
class Safe:
def __init__(self, secret):
self.__secret = secret # → _Safe__secret 으로 저장됨
파이썬은 __attr를 _ClassName__attr로 자동 변환합니다.
| 항목 | 식 | 결과 | 이유 |
|---|---|---|---|
| ① | hasattr(s, "_Safe__secret") |
True |
실제 저장 이름 |
| ② | hasattr(s, "__secret") |
False |
이 이름으로는 접근 불가 |
| ③ | s.reveal() 출력 후 True |
True |
클래스 내부에서는 self.__secret 접근 가능 |
| ④ | s.reveal() |
I have a secret. |
메서드 내부에서 정상 접근 |
외부에서 s.__secret으로 접근하면 AttributeError가 발생합니다.
문제 8. 클래스 변수 카운터 (빈칸 정답)¶
class Counter:
count = 0 # 클래스 변수
def __init__(self):
Counter.count += 1 # 클래스 이름으로 접근해야 클래스 변수 수정 가능
@classmethod
def get_count(cls):
return cls.count # cls는 클래스 자체를 가리킴
빈칸 정답
| 빈칸 위치 | 정답 | 이유 |
|---|---|---|
______ = 0 |
count |
클래스 변수 이름 |
______.count += 1 |
Counter |
클래스 이름으로 클래스 변수 수정 |
def get_count(______): |
cls |
classmethod의 첫 매개변수 |
return ______.count |
cls |
cls가 Counter 클래스를 가리킴 |
실행 결과: 3
문제 9. 상속 체인 (빈칸 정답)¶
class Vehicle:
def __init__(self, speed):
self.speed = speed
class Car(Vehicle):
def __init__(self, speed, brand):
super().__init__(speed)
self.brand = brand
class ElectricCar(Car):
def __init__(self, speed, brand, range_km):
super().__init__(speed, brand)
self.range_km = range_km
def info(self):
return f"{self.brand} {self.speed}km/h range:{self.range_km}km"
빈칸 정답
| 빈칸 위치 | 정답 | 이유 |
|---|---|---|
class Car(______): |
Vehicle |
Car가 Vehicle을 상속 |
super().__init__(______) (Car) |
speed |
Vehicle의 생성자에 speed 전달 |
class ElectricCar(______): |
Car |
ElectricCar가 Car를 상속 |
super().__init__(______, ______) (ElectricCar) |
speed, brand |
Car의 생성자에 두 인자 전달 |
실행 결과: Tesla 200km/h range:500km
문제 10. 은행 계좌 클래스 (빈칸 정답)¶
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance
def deposit(self, amount):
if amount > 0:
self.__balance += amount
def withdraw(self, amount):
if amount > 0 and amount <= self.__balance:
self.__balance -= amount
return True
return False
def __str__(self):
return f"{self.owner}: {self.__balance}원"
빈칸 정답
| 빈칸 위치 | 정답 | 이유 |
|---|---|---|
self.______ (owner) |
owner |
인스턴스 변수 |
self.______balance |
__ (이중 언더스코어) |
외부 접근 차단 (name mangling) |
self.__balance ______ amount (deposit) |
+= |
잔액 증가 |
amount <= self.______ |
__balance |
출금 가능 여부 확인 |
return f"... {self.______}원" |
__balance |
잔액 출력 |
실행 결과:
Alice: 1500원
True
Alice: 1000원