본문 바로가기
C.W.K.
Stream
Lesson 05 of 07 · published

상속과 합성 — is-a와 has-a를 구분하기

~22 min · inheritance, super, composition, subclass

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

상속은 대체 가능한 종류 관계야

서브클래스가 부모가 기대되는 자리에 들어가 같은 약속을 지킬 때 상속이 자연스러워. super()는 이름 붙인 부모를 직접 부르는 대신 MRO의 다음 구현에 협력하며, 초기화와 메서드를 덮어쓰거나 앞뒤로 확장할 수 있어.

재사용만을 위해 상속하지 마

객체가 다른 객체를 가지고 일을 맡기는 관계라면 합성이 더 선명해. 내부 부품을 바꾸고 시험하기 쉽고, 부모의 숨은 상태와 수명에 묶이지 않아.

객체는 정체성과 책임이 있을 때 태어나

객체지향은 모든 계산을 클래스로 감싸는 규칙이 아니야. 지속되는 정체성과 지켜야 할 상태 변화가 있으면 객체를 만들고, 순수한 변환은 함수로 두는 선택도 좋은 객체 설계야.

Code

상속과 super로 초기화 이어가기·python
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} 가 소리냄"

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)            # Animal 이 자기 부분 init
        self.breed = breed

    def speak(self):                       # override
        return f"{self.name} ({self.breed}) 가 짖음"

d = Dog("Rex", "Lab")
print(d.name)              # 'Rex'  — Animal __init__ 에서 상속
print(d.breed)             # 'Lab'
print(d.speak())           # 'Rex (Lab) 가 짖음'
부모 동작을 없애지 않고 확장하기·python
class Logger:
    def log(self, msg):
        print(f"[LOG] {msg}")

class TimestampedLogger(Logger):
    def log(self, msg):
        import datetime
        stamped = f"{datetime.datetime.now().isoformat()}: {msg}"
        super().log(stamped)         # 변경된 msg 로 부모 버전 호출

tl = TimestampedLogger()
tl.log("hello")
# [LOG] 2026-05-02T12:34:56.789: hello
isinstance와 issubclass로 관계 확인하기·python
class Animal: pass
class Dog(Animal): pass
class Lab(Dog): pass

l = Lab()
print(isinstance(l, Lab))      # True
print(isinstance(l, Dog))      # True   — Lab 이 Dog 상속
print(isinstance(l, Animal))   # True   — Animal 도

print(issubclass(Lab, Animal)) # True
print(issubclass(Dog, Lab))    # False  — Dog 는 부모, 서브클래스가 아님

# isinstance 는 타입 tuple 받음
print(isinstance(l, (Lab, str)))   # True
같은 문제를 상속과 합성으로 풀어 보기·python
# 상속 — Car IS an Engine. 잘못된 관계.
class Engine:
    def start(self):
        return "vroom"

class CarBad(Engine):                # 안 좋음 — Car 가 Engine 아님
    def drive(self):
        return self.start() + " go"

# 합성 — Car HAS an Engine. 맞는 관계.
class CarGood:
    def __init__(self):
        self.engine = Engine()       # 합성

    def drive(self):
        return self.engine.start() + " go"

c = CarGood()
print(c.drive())

# 엔진 교체 쉬움
class ElectricMotor:
    def start(self):
        return "hum"

c.engine = ElectricMotor()           # 구현 교체, 상속을 바꾸지 않음
print(c.drive())                     # 'hum go'

External links

Exercise

이름과 describe를 가진 Shape, width·height를 가진 Rectangle, radius를 가진 Circle을 만들어. 두 하위 클래스는 super로 초기화하고 describe에 치수를 덧붙여. 이어서 shape 목록을 소유하는 Drawing을 합성으로 만들고 add와 show를 시험해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.