본문으로 건너뛰기

단원 연습 문제

파이썬 목차클래스문제 12개

클래스 · 객체 · __init__ · self · 메서드 · 상속을 섞었습니다. 앞 단원의 리스트 · 함수 · 변수의 범위도 함께 묻고, 어느 레슨의 문제인지는 정답을 펼쳐야 보입니다. 출력을 쓰는 문제는 빈칸과 줄바꿈까지 종이에 끝까지 쓴 뒤 정답을 펼치세요. 막히면 정답 앞의 힌트를 먼저 펼칩니다. 점수는 매기지 않습니다.

한 번에 다 풀 필요는 없습니다. 문제 1~10은 폰으로도 풀 수 있고(약 20~25분), 끝의 만들어 보기 둘(문제 11·12)은 이 쪽의 실행 칸이나 컴퓨터에서 돌려 맞춰 보세요. 이 단원을 이미 안다면 문제 1 · 3 · 5 · 7만 힌트 없이 먼저 풀어 보세요(약 10분). 네 문제를 다 맞히면 다음 단원으로 넘어가고, 틀린 문제는 정답 끝의 레슨으로 돌아가 그 레슨만 봅니다.

객체를 다룰 때는 이름이 어느 객체(①, ②)에 붙어 있는지 이름표를 그리며 따라가세요. 실행 결과는 모두 파이썬 3.15로 돌린 것입니다.

문제 1

무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

class StampCard:
    pass


a = StampCard()
b = StampCard()
a.stamps = 2
b.stamps = 5
a.stamps = a.stamps + 1
print(a.stamps)
print(b.stamps)
힌트

StampCard()를 두 번 불렀으니 객체가 몇 개 생겼는지, 9번 줄이 어느 객체의 .stamps를 바꾸는지 보세요.

정답
실행 결과
3
5

StampCard()를 부를 때마다 서로 다른 새 객체(①, ②)가 만들어집니다(규칙 3). a.stamps를 2에서 3으로 바꿔도 b가 가리키는 객체 ②의 .stamps는 5 그대로입니다.

다시 볼 레슨: 클래스와 객체

문제 2

다음 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.

class Box:
    pass


b = Box()
print(b.weight)
  • ① 0이 찍힌다
  • ② None이 찍힌다
  • ③ 6번 줄에서 AttributeError가 난다
힌트

5번 줄에서 만든 빈 객체 b 안에 .weight 속성을 넣은 적이 있는지 보세요.

정답

③ — 실행 결과는 이렇습니다.

실행 결과
Traceback (most recent call last):  File "main.py", line 6, in <module>    print(b.weight)          ^^^^^^^^AttributeError: 'Box' object has no attribute 'weight'

아직 만들지 않은 속성을 읽으려 하면 0이나 None이 나오는 것이 아니라 AttributeError가 납니다.

다시 볼 레슨: 클래스와 객체

문제 3

무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

class Member:
    def __init__(self, s, p=10):
        self.name = s
        self.pt = p


m1 = Member('민지')
m2 = Member('준호', 30)
print(m1.name, m1.pt)
print(m2.name, m2.pt)
힌트

7번 줄은 두 번째 인자를 생략했으니 기본값 10을 쓰고, 8번 줄은 30을 넘겼습니다.

정답
실행 결과
민지 10
준호 30

객체를 만들 때 파이썬이 자동으로 __init__을 부르고 첫 번째 매개변수 self에 새 객체를 넘깁니다(규칙 5). m1은 기본값 10으로, m2는 넘긴 30으로 .pt가 채워집니다.

다시 볼 레슨: __init__과 self · 기본값과 키워드 인자

문제 4

다음 코드를 실행하면 어떻게 될까요? 알맞은 것을 고르세요.

class Timer:
    def __init__(self, sec):
        left = sec


t = Timer(30)
print(t.left)
  • ① 30이 찍힌다
  • ② 3번 줄에서 NameError가 난다
  • ③ 7번 줄에서 AttributeError가 난다
힌트

3번 줄 left = sec에 self.이 붙어 있는지 보세요.

정답

③ — 실행 결과는 이렇습니다.

실행 결과
Traceback (most recent call last):  File "main.py", line 7, in <module>    print(t.left)          ^^^^^^AttributeError: 'Timer' object has no attribute 'left'

3번 줄 left = sec는 self. 없이 적었으므로 __init__ 함수 칸 안에서만 쓰이다 사라지는 지역 변수입니다(규칙 5). 객체 t에는 .left 속성이 생기지 않아 7번 줄에서 AttributeError가 납니다.

다시 볼 레슨: __init__과 self · 함수 안의 이름, 밖의 이름

문제 5

무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.

class Counter:
    def __init__(self, start):
        self.val = start

    def step(self, n=1):
        self.val += n


c1 = Counter(10)
c2 = Counter(0)
c1.step()
c2.step(5)
c1.step(2)
print(c1.val, c2.val)
힌트

c1.step()을 부를 때 self가 어느 객체를 가리키는지, c2.step(5)를 부를 때 self가 어느 객체를 가리키는지 차례로 따라가 보세요.

정답
실행 결과
13 5
  • c1은 10에서 시작해 step()으로 1 오르고 step(2)로 2 올라 13이 됩니다.
  • c2는 0에서 시작해 step(5)로 5 올라 5가 됩니다.

다시 볼 레슨: 메서드

문제 6

빈칸 (가)와 (나)에 들어갈 파이썬 이름을 쓰세요.

  • 클래스로 새 객체를 만들 때 파이썬이 자동으로 불러 처음 속성을 채우는 메서드의 이름은 앞뒤에 밑줄을 두 개씩 붙인 (가)이다.
  • 메서드 정의의 첫 번째 매개변수로 적어 호출한 객체 자신을 가리키는 관례 이름은 (나)이다.
힌트

def ____(____, ...):의 두 자리에 늘 적던 이름을 떠올려 보세요.

정답
  • (가) __init__
  • (나) self

다시 볼 레슨: __init__과 self · 메서드

문제 7

무엇이 찍힐까요? 두 줄을 글자 그대로 쓰세요.

class StampCard:
    def __init__(self, owner):
        self.owner = owner
        self.stamps = 0
    def add(self):
        self.stamps += 1
class VipCard(StampCard):
    def add(self):
        self.stamps += 2
a = StampCard('민지')
b = VipCard('준호')
a.add()
b.add()
print(a.owner, a.stamps)
print(b.owner, b.stamps)
힌트

VipCard는 __init__을 부모 StampCard에서 물려받고, add는 자기가 다시 정의한 것을 씁니다.

정답
실행 결과
민지 1
준호 2

a는 StampCard 객체이므로 a.add()가 스탬프를 1 올리고, b는 VipCard 객체이므로 오버라이딩한 VipCard.add가 실행되어 스탬프를 2 올립니다.

다시 볼 레슨: 상속

문제 8

자식 클래스 BonusCard의 __init__에서 부모 클래스 StampCard의 __init__을 먼저 불러 self.owner와 self.stamps를 초기화하려고 합니다. 빈칸에 들어갈 한 줄을 쓰세요.

class StampCard:
    def __init__(self, s):
        self.owner = s
        self.stamps = 0


class BonusCard(StampCard):
    def __init__(self, s, b):
        ____________________
        self.stamps += b


c = BonusCard('민지', 3)
print(c.owner, c.stamps)
힌트

부모 클래스를 가리키는 super() 뒤에 .__init__(...)을 붙입니다. self는 다시 넘기지 않습니다.

정답

super().__init__(s)입니다.

class StampCard:
    def __init__(self, s):
        self.owner = s
        self.stamps = 0


class BonusCard(StampCard):
    def __init__(self, s, b):
        super().__init__(s)
        self.stamps += b


c = BonusCard('민지', 3)
print(c.owner, c.stamps)
실행 결과
민지 3

다시 볼 레슨: 상속

문제 9

두 변수가 같은 객체를 가리킬 때와 서로 다른 객체를 가리킬 때를 견줍니다. 무엇이 찍힐까요? 한 줄을 글자 그대로 쓰세요.

class Bag:
    def __init__(self):
        self.items = []


b1 = Bag()
b2 = b1
b3 = Bag()
b2.items.append('사과')
b3.items.append('우유')
print(b1.items, b3.items)
힌트

7번 줄 b2 = b1은 새 객체를 만들지 않고 b1과 같은 객체에 이름표만 하나 더 붙입니다(규칙 3).

정답
실행 결과
['사과'] ['우유']

b2 = b1은 b1이 가리키는 객체 ①에 b2라는 이름표를 하나 더 붙인 것이므로 b2.items.append('사과')⁠를 하면 b1.items에서도 ['사과']가 보입니다(규칙 3). 반면 b3 = Bag()는 새로 만든 객체 ②이므로 ['우유']만 들어 있습니다.

다시 볼 레슨: 클래스와 객체 · 리스트와 이름 둘

문제 10

아래 코드는 Wallet 객체에 돈을 넣는 put 메서드를 부르려다 오류가 납니다. 잘못된 두 줄(6번 줄과 7번 줄)을 어떻게 고쳐야 3000이 찍힐까요?

class Wallet:
    def __init__(self):
        self.money = 1000

    def put(won):
        money += won


w = Wallet()
w.put(2000)
print(w.money)
힌트

메서드 정의의 첫 번째 매개변수에는 무엇이 들어가야 하는지, 그리고 객체의 .money 속성을 바꿀 때 이름 앞에 무엇을 붙여야 하는지 보세요.

정답

5번 줄을 def put(self, won):으로, 6번 줄을 self.money += won으로 고칩니다.

class Wallet:
    def __init__(self):
        self.money = 1000

    def put(self, won):
        self.money += won


w = Wallet()
w.put(2000)
print(w.money)
실행 결과
3000

메서드의 첫 번째 매개변수로 self를 받아야 호출한 객체 w가 연결되고, 메서드 안에서 속성을 읽고 바꿀 때도 self.money처럼 self.을 붙여야 합니다.

다시 볼 레슨: 메서드

문제 11 (만들어 보기)

스탬프 개수 .n을 0으로 시작해 모으고, 10개 이상인지(True/False) 알려 주는 StampCard 클래스를 완성하세요. 뼈대의 마지막 줄이 이렇게 찍어야 합니다.

10 True

끝에 c2 = StampCard() · c2.add(5) · print(c2.n, c2.free())⁠를 더해 한 번 더 부르면 이렇게 나와야 합니다.

10 True
5 False

아래 뼈대에서 주석 자리 # 1과 # 2를 채우세요.

class StampCard:
    def __init__(self):
        self.n = 0
    def add(self, k=1):
        # 1. self.n에 k 더하기
        pass
    def free(self):
        # 2. 10 이상인지 돌려주기
        pass

c = StampCard()
c.add(7)
c.add(3)
print(c.n, c.free())

처음 펼 때 약 6MB를 받습니다.

힌트

add에서는 self.n += k를 실행하고, free에서는 return self.n >= 10을 돌려줍니다.

정답
class StampCard:
    def __init__(self):
        self.n = 0

    def add(self, k=1):
        self.n += k

    def free(self):
        return self.n >= 10

c = StampCard()
c.add(7)
c.add(3)
print(c.n, c.free())
실행 결과
10 True

다시 볼 레슨: __init__과 self · 메서드

문제 12 (만들어 보기)

장바구니 Cart 클래스를 상속받아, 담을 때마다 가격 p에서 500원을 깎아 더하는 SaleCart 클래스를 작성하세요.

  • 부모 클래스 Cart는 이미 주어져 있습니다(self.total = 0, add(self, p)는 self.total += p).
  • 자식 클래스 SaleCart(Cart)에서 add(self, p) 메서드를 오버라이딩해 p - 500만큼 self.total에 더하도록 만드세요.

4000원과 4500원을 담으면 이렇게 나와야 합니다.

7500

끝에 bag.add(3500)과 print(bag.total)을 더하면 이렇게 나와야 합니다.

7500
10500
class Cart:
    def __init__(self):
        self.total = 0

    def add(self, p):
        self.total += p

# 여기에 SaleCart 클래스를 작성하세요

bag = SaleCart()
bag.add(4000)
bag.add(4500)
print(bag.total)

처음 펼 때 약 6MB를 받습니다.

힌트

class SaleCart(Cart): 안에 def add(self, p):를 만들고 self.total += p - 500⁠을 적습니다.

정답
class Cart:
    def __init__(self):
        self.total = 0

    def add(self, p):
        self.total += p

class SaleCart(Cart):
    def add(self, p):
        self.total += p - 500

bag = SaleCart()
bag.add(4000)
bag.add(4500)
print(bag.total)
실행 결과
7500

SaleCart는 __init__을 따로 적지 않았으므로 부모 Cart의 __init__을 물려받아 self.total = 0으로 시작하고, add만 덮어써서 할인가를 더합니다.

다시 볼 레슨: 상속 · 메서드

끝까지 내려오면 저절로 표시됩니다. 이 기기에만 저장합니다.

파이썬 목차로