목차
1. 레거시 프로젝트의 반복 코드
입사 첫날, 팀장님이 Fantasy MMORPG라는 Git 저장소를 보내줬다고 가정해보겠습니다. 코드를 열어보니 전사, 마법사, 궁수 클래스가 각각 따로 작성되어 있습니다.
전사 클래스
class Warrior:
def __init__(self):
self.hp = 100
self.mp = 20
def move(self):
print("이동")
def attack(self):
print("공격")마법사 클래스
class Wizard:
def __init__(self):
self.hp = 80
self.mp = 200
def move(self):
print("이동")
def attack(self):
print("공격")궁수 클래스
class Archer:
def __init__(self):
self.hp = 90
self.mp = 50
def move(self):
print("이동")
def attack(self):
print("공격")뭔가 이상하지 않나요? move()와 attack() 같은 코드가 클래스마다 계속 반복되고 있습니다.
2. 상속이 필요한 이유
개발자가 가장 싫어하는 것 중 하나는 반복입니다. 캐릭터가 3개일 때는 괜찮아 보이지만 게임이 성장하면 문제가 커집니다.
- 전사
- 마법사
- 궁수
- 도적
- 기사
- 성기사
- 암살자
- 소환사
- 드루이드
- 바드
100개 클래스가 생긴다면 같은 코드를 100번 복사해야 합니다. 이것은 개발자의 악몽입니다.
현실 세계에서 배우는 상속
상속을 이해하려면 가족을 떠올리면 됩니다. 아버지, 아들, 딸은 성씨, 눈 색깔, 혈액형 같은 많은 특징을 공유할 수 있습니다.
| 대상 | 물려받는 특징 |
|---|---|
| 아버지 | 성씨, 눈 색깔, 혈액형 |
| 아들 | 성씨, 눈 색깔, 혈액형 |
| 딸 | 성씨, 눈 색깔, 혈액형 |
프로그래밍도 같습니다. 공통 기능은 부모에게 만들고 자식은 물려받습니다. 이것이 상속 Inheritance입니다.
3. 부모 클래스 만들기
먼저 공통 기능을 하나의 부모 클래스에 모아보겠습니다.
class Character:
def move(self):
print("이동")
def attack(self):
print("기본 공격")이 Character 클래스는 모든 캐릭터의 부모가 됩니다. 이동과 기본 공격처럼 여러 캐릭터가 공통으로 사용하는 기능을 여기에 둡니다.
4. 자식 클래스와 공통 기능 재사용
첫 번째 상속: 전사 만들기
class Warrior(Character):
pass전사 객체를 생성합니다.
warrior = Warrior()부모 클래스에 있던 메서드를 실행합니다.
warrior.move()
warrior.attack()결과입니다.
이동
기본 공격Warrior 클래스 안에는 move()와 attack()을 작성하지 않았지만 사용할 수 있습니다. 부모에게서 물려받았기 때문입니다.
마법사도 상속받기
class Wizard(Character):
passwizard = Wizard()
wizard.move()
wizard.attack()결과입니다.
이동
기본 공격상속의 진짜 매력
팀장님이 모든 캐릭터에 점프 기능을 추가해달라고 요청했다고 가정해보겠습니다. 상속이 없다면 100개 클래스를 수정해야 합니다. 상속이 있다면 부모 클래스 하나만 수정하면 됩니다.
class Character:
def jump(self):
print("점프")부모를 업그레이드하면 자식도 함께 업그레이드됩니다. 이것이 상속이 사랑받는 이유입니다.
5. 오버라이딩 Overriding
상속에는 문제가 하나 있습니다. 이동은 같아도 공격은 캐릭터마다 달라야 할 수 있습니다.
| 캐릭터 | 공격 방식 |
|---|---|
| 전사 | 검 공격 |
| 마법사 | 파이어볼 |
| 궁수 | 화살 발사 |
이럴 때 사용하는 것이 오버라이딩 Overriding입니다.
부모 코드
class Character:
def attack(self):
print("기본 공격")자식이 재정의
class Warrior(Character):
def attack(self):
print("검 공격")실행합니다.
warrior = Warrior()
warrior.attack()결과입니다.
검 공격자식 클래스가 부모 클래스의 기능을 다시 정의해 덮어쓰는 것을 오버라이딩이라고 합니다.
6. 실무와 프레임워크의 상속
자동차 시스템
자동차 시스템에서도 상속을 생각할 수 있습니다.
| 구분 | 예시 |
|---|---|
| 부모 클래스 | Car |
| 공통 기능 | 시동걸기, 정지하기, 주행하기 |
| 자식 클래스 | Tesla, BMW, Hyundai |
class Car:class Tesla(Car):class BMW(Car):class Hyundai(Car):각 브랜드는 공통 기능을 Car에서 물려받을 수 있습니다.
웹 개발에서도 사용된다
Django, FastAPI, Flask 같은 웹 개발 환경에서도 실제로 많은 클래스가 상속 구조를 사용합니다.
class User(BaseModel):class Product(BaseModel):BaseModel이 부모이고 User, Product가 자식입니다.
AI 프레임워크도 상속 천국
PyTorch와 TensorFlow에서도 상속은 매우 자주 등장합니다.
| 프레임워크 | 예시 코드 | 의미 |
|---|---|---|
| PyTorch | class MyModel(nn.Module): | nn.Module을 상속해 사용자 모델을 정의합니다. |
| TensorFlow | class CustomLayer(Layer): | Layer를 상속해 사용자 레이어를 정의합니다. |
class MyModel(nn.Module):class CustomLayer(Layer):딥러닝 모델 대부분은 상속 기반 구조를 사용합니다. AI 개발자가 되더라도 상속은 반드시 만나게 됩니다.
7. super()와 부모 기능 호출
어느 날 전사는 부모 기능도 필요하고 자기 기능도 필요해졌습니다. 이때 super()를 사용합니다.
class Character:
def attack(self):
print("기본 공격")class Warrior(Character):
def attack(self):
super().attack()
print("검 공격")실행 결과입니다.
기본 공격
검 공격super()는 부모 클래스의 기능을 호출하는 명령입니다. 부모 동작을 유지하면서 자식만의 동작을 추가할 때 유용합니다.
8. 상속 계층과 과사용 주의
실제 회사 프로젝트에는 상속 계층이 존재할 수 있습니다.
LivingThing
↓
Character
↓
Player
↓
WarriorLivingThing
↓
Character
↓
Monster
↓
Dragon이런 계층 구조는 조직도처럼 공통 기능과 구체 기능을 단계적으로 나눕니다.
상속을 너무 많이 쓰면?
상속은 강력하지만 과하면 독이 됩니다.
A
↓
B
↓
C
↓
D
↓
E
↓
F상속 단계가 너무 깊어지면 코드 흐름을 추적하기 어려워집니다. 실무에서는 보통 2~3단계 정도의 단순한 상속 구조를 선호합니다.
9. 상속을 이해한 개발자의 차이
상속이 없었다면 운영체제, 웹브라우저, 게임, AI, ERP, 은행 시스템은 지금보다 훨씬 복잡했을 것입니다. 상속은 소프트웨어 세계의 복사와 붙여넣기 제거 기술이라고 볼 수 있습니다.
| 구분 | 작성 방식 | 결과 |
|---|---|---|
| 초보 개발자 | Warrior, Wizard, Archer에 모든 코드를 직접 작성 | 코드 반복 증가 |
| 숙련 개발자 | Character에 공통 기능을 만들고 Warrior(Character)처럼 상속 | 코드 양 감소와 유지보수 향상 |
초보 개발자는 모든 코드를 직접 작성합니다.
class Warrior:class Wizard:class Archer:숙련 개발자는 공통 기능을 재사용합니다.
class Character:class Warrior(Character):class Wizard(Character):class Archer(Character):- 공통 기능 재사용
- 코드 양 감소
- 수정 범위 축소
- 유지보수 향상
- 객체 관계 설계 가능
10. 정리와 다음 편 예고
오늘 배운 내용을 한 문장으로 정리하면 상속 Inheritance은 부모 클래스의 능력을 자식 클래스가 물려받는 기술이며, 객체지향 프로그래밍의 핵심 재사용 전략입니다.
- 상속은 공통 기능을 부모 클래스에 두고 자식 클래스가 물려받는 구조입니다.
- class Warrior(Character)처럼 작성하면 Warrior는 Character를 상속합니다.
- 부모 클래스에 기능을 추가하면 자식 클래스에서도 사용할 수 있습니다.
- 오버라이딩은 자식 클래스가 부모 기능을 다시 정의하는 기술입니다.
- super()는 부모 클래스의 기능을 호출합니다.
- 상속은 강력하지만 너무 깊게 사용하면 유지보수가 어려워질 수 있습니다.
- 웹 프레임워크와 AI 프레임워크에서도 상속은 자주 등장합니다.
지난 시간에는 Class를 배웠고, 이번 시간에는 Inheritance를 배웠습니다. 이제 단순히 객체를 만드는 수준을 넘어 객체들의 관계를 설계할 수 있게 되었습니다. 이것이 실제 소프트웨어 설계의 시작입니다.
- 다형성 Polymorphism 이해하기
- 같은 명령어가 객체에 따라 다르게 동작하는 원리
- 전사에게 attack을 호출하면 검 공격, 마법사에게 호출하면 파이어볼이 나가는 이유
