728x90
반응형
Overview
상속(Inheritance)과 다형성(Polymorphism)은 객체지향 프로그래밍의 핵심 개념이다. 코드 재사용성을 높이고, 유지보수를 쉽게 만들며, 확장 가능한 구조를 설계할 수 있게 해준다.

1. 상속 기본 개념
상속은 기존 클래스의 속성과 메서드를 새로운 클래스가 물려받는 것을 말한다.
기본 상속 구조
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
return "동물이 소리를 냅니다"
def move(self):
return f"{self.name}이(가) 움직입니다"
class Dog(Animal): # Animal을 상속
def speak(self): # 메서드 오버라이딩
return "멍멍!"
class Cat(Animal):
def speak(self):
return "야옹!"
# 사용
dog = Dog("바둑이")
cat = Cat("나비")
print(dog.name) # 바둑이 (상속받은 속성)
print(dog.speak()) # 멍멍! (오버라이딩된 메서드)
print(dog.move()) # 바둑이이(가) 움직입니다 (상속받은 메서드)
print(cat.speak()) # 야옹!
용어 정리
- 부모 클래스(Parent Class) / 슈퍼 클래스(Super Class) / 베이스 클래스(Base Class): Animal
- 자식 클래스(Child Class) / 서브 클래스(Sub Class) / 파생 클래스(Derived Class): Dog, Cat
2. super() 함수
`super()` 는 부모 클래스의 메서드를 호출할 때 사용한다.
super()로 부모 클래스 초기화
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
return f"안녕하세요, {self.name}입니다. {self.age}살입니다."
class Student(Person):
def __init__(self, name, age, student_id):
super().__init__(name, age) # 부모 클래스의 __init__ 호출
self.student_id = student_id
def introduce(self):
parent_intro = super().introduce() # 부모의 introduce() 호출
return f"{parent_intro} 학번: {self.student_id}"
student = Student("김철수", 20, "2024001")
print(student.introduce())
# 안녕하세요, 김철수입니다. 20살입니다. 학번: 2024001
super() vs 직접 호출
class Parent:
def method(self):
return "부모 메서드"
class Child(Parent):
def method(self):
# 방법 1: super() 사용 (권장)
return super().method() + " + 자식 메서드"
def method_old_style(self):
# 방법 2: 직접 호출 (비권장)
return Parent.method(self) + " + 자식 메서드"
`super()` 를 사용하는 이유
- 다중 상속에서 올바른 MRO를 따름
- 코드 유지보수가 쉬움
- 부모 클래스가 변경되어도 자식 클래스 수정 불필요
3. 메서드 오버라이딩 (Method Overriding)
자식 클래스가 부모 클래스의 메서드를 재정의하는 것이다.
class Shape:
def __init__(self, color):
self.color = color
def area(self):
raise NotImplementedError("서브클래스에서 구현해야 합니다")
def describe(self):
return f"{self.color} 도형"
class Circle(Shape):
def __init__(self, color, radius):
super().__init__(color)
self.radius = radius
def area(self): # 오버라이딩
return 3.14159 * self.radius ** 2
def describe(self): # 오버라이딩
return f"{super().describe()}: 원 (반지름: {self.radius})"
class Rectangle(Shape):
def __init__(self, color, width, height):
super().__init__(color)
self.width = width
self.height = height
def area(self): # 오버라이딩
return self.width * self.height
def describe(self):
return f"{super().describe()}: 직사각형 ({self.width}x{self.height})"
circle = Circle("빨강", 5)
rectangle = Rectangle("파랑", 4, 6)
print(circle.area()) # 78.53975
print(circle.describe()) # 빨강 도형: 원 (반지름: 5)
print(rectangle.area()) # 24
print(rectangle.describe()) # 파랑 도형: 직사각형 (4x6)
4. 다형성 (Polymorphism)
다형성은 같은 인터페이스로 다른 동작을 수행하는 것을 의미한다.
class Bird:
def fly(self):
return "새가 하늘을 납니다"
class Airplane:
def fly(self):
return "비행기가 하늘을 납니다"
class Butterfly:
def fly(self):
return "나비가 하늘을 날아다닙니다"
# 다형성: 같은 메서드 이름, 다른 동작
def make_it_fly(flying_object):
print(flying_object.fly())
bird = Bird()
plane = Airplane()
butterfly = Butterfly()
make_it_fly(bird) # 새가 하늘을 납니다
make_it_fly(plane) # 비행기가 하늘을 납니다
make_it_fly(butterfly) # 나비가 하늘을 날아다닙니다
덕 타이핑 (Duck Typing): Python은 "오리처럼 걷고, 오리처럼 꽥꽥거리면, 그것은 오리다"라는 철학을 따른다. 타입보다는 동작이 중요하다.
# 상속 관계가 없어도 같은 메서드만 있으면 OK!
class Dog:
def speak(self):
return "멍멍!"
class Cat:
def speak(self):
return "야옹!"
class Robot:
def speak(self):
return "삐빅!"
def animal_sound(obj):
print(obj.speak()) # 어떤 타입이든 speak()만 있으면 됨
animal_sound(Dog()) # 멍멍!
animal_sound(Cat()) # 야옹!
animal_sound(Robot()) # 삐빅!
5. 추상 클래스 (Abstract Base Class)
추상 클래스는 인스턴스를 생성할 수 없으며, 자식 클래스에서 반드시 구현해야 하는 메서드를 정의한다.
from abc import ABC, abstractmethod
class Vehicle(ABC): # ABC를 상속
def __init__(self, brand):
self.brand = brand
@abstractmethod
def start_engine(self):
"""서브클래스에서 반드시 구현해야 함"""
pass
@abstractmethod
def stop_engine(self):
"""서브클래스에서 반드시 구현해야 함"""
pass
def honk(self):
return f"{self.brand} 경적: 빵빵!"
class Car(Vehicle):
def start_engine(self):
return f"{self.brand} 자동차 시동을 켭니다"
def stop_engine(self):
return f"{self.brand} 자동차 시동을 끕니다"
class Motorcycle(Vehicle):
def start_engine(self):
return f"{self.brand} 오토바이 시동을 켭니다"
def stop_engine(self):
return f"{self.brand} 오토바이 시동을 끕니다"
# vehicle = Vehicle("현대") # 에러! 추상 클래스는 인스턴스 생성 불가
car = Car("현대")
motorcycle = Motorcycle("혼다")
print(car.start_engine()) # 현대 자동차 시동을 켭니다
print(car.honk()) # 현대 경적: 빵빵!
print(motorcycle.start_engine()) # 혼다 오토바이 시동을 켭니다
6. 다중 상속 (Multiple Inheritance)
Python은 여러 부모 클래스로부터 상속받을 수 있다.
class Flyable:
def fly(self):
return "날 수 있습니다"
class Swimmable:
def swim(self):
return "헤엄칠 수 있습니다"
class Duck(Flyable, Swimmable):
def __init__(self, name):
self.name = name
def quack(self):
return "꽥꽥!"
duck = Duck("도널드")
print(duck.fly()) # 날 수 있습니다
print(duck.swim()) # 헤엄칠 수 있습니다
print(duck.quack()) # 꽥꽥!
MRO (Method Resolution Order)
다중 상속에서 메서드 탐색 순서를 나타낸다.
class A:
def method(self):
return "A"
class B(A):
def method(self):
return "B"
class C(A):
def method(self):
return "C"
class D(B, C):
pass
d = D()
print(d.method()) # B
print(D.mro()) # MRO 확인
# [<class '__main__.D'>, <class '__main__.B'>,
# <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
MRO 규칙
- 자식 클래스가 먼저
- 부모 클래스는 선언 순서대로
- 같은 부모는 한 번만
- 최상위는 항상 object
7. 실전 예제: 직원 관리 시스템
모든 개념을 활용한 완전한 예제다.
from abc import ABC, abstractmethod
from datetime import datetime
class Employee(ABC):
"""직원 추상 클래스"""
employee_count = 0
def __init__(self, name, employee_id):
self.name = name
self.employee_id = employee_id
self.hire_date = datetime.now()
Employee.employee_count += 1
@abstractmethod
def calculate_salary(self):
"""급여 계산 - 서브클래스에서 구현 필수"""
pass
@abstractmethod
def get_role(self):
"""직책 반환 - 서브클래스에서 구현 필수"""
pass
def get_info(self):
return f"[{self.employee_id}] {self.name} - {self.get_role()}"
@classmethod
def get_employee_count(cls):
return cls.employee_count
class Developer(Employee):
"""개발자 클래스"""
def __init__(self, name, employee_id, programming_languages, level):
super().__init__(name, employee_id)
self.programming_languages = programming_languages
self.level = level # junior, senior, lead
def calculate_salary(self):
base_salary = 3000000
level_bonus = {
'junior': 0,
'senior': 1000000,
'lead': 2000000
}
return base_salary + level_bonus.get(self.level, 0)
def get_role(self):
return f"{self.level.capitalize()} Developer"
def write_code(self, language):
if language in self.programming_languages:
return f"{self.name}이(가) {language}로 코드를 작성합니다"
return f"{self.name}은(는) {language}를 모릅니다"
class Designer(Employee):
"""디자이너 클래스"""
def __init__(self, name, employee_id, specialty):
super().__init__(name, employee_id)
self.specialty = specialty # UI/UX, Graphic, etc.
def calculate_salary(self):
return 3500000
def get_role(self):
return f"{self.specialty} Designer"
def create_design(self, project):
return f"{self.name}이(가) {project}의 디자인을 작성합니다"
class Manager(Employee):
"""매니저 클래스"""
def __init__(self, name, employee_id, team_size):
super().__init__(name, employee_id)
self.team_size = team_size
self.team_members = []
def calculate_salary(self):
base_salary = 5000000
team_bonus = self.team_size * 100000
return base_salary + team_bonus
def get_role(self):
return f"Manager (팀원 {self.team_size}명)"
def add_team_member(self, employee):
self.team_members.append(employee)
self.team_size = len(self.team_members)
def get_team_info(self):
team_info = [f"\n{self.name}의 팀:"]
for member in self.team_members:
team_info.append(f" - {member.get_info()}")
return "\n".join(team_info)
# 다형성을 활용한 급여 계산
def print_salary_info(employees):
print("=== 급여 명세서 ===")
total = 0
for emp in employees:
salary = emp.calculate_salary()
total += salary
print(f"{emp.get_info()}: {salary:,}원")
print(f"\n총 급여: {total:,}원")
print(f"총 직원 수: {Employee.get_employee_count()}명")
# 사용 예시
dev1 = Developer("김개발", "DEV001", ["Python", "JavaScript"], "senior")
dev2 = Developer("이코드", "DEV002", ["Java", "Kotlin"], "junior")
designer = Designer("박디자인", "DES001", "UI/UX")
manager = Manager("최매니저", "MGR001", 0)
# 팀 구성
manager.add_team_member(dev1)
manager.add_team_member(dev2)
manager.add_team_member(designer)
# 직원 목록
employees = [dev1, dev2, designer, manager]
# 다형성: 모든 직원 타입에 동일한 함수 적용
print_salary_info(employees)
print(manager.get_team_info())
print(f"\n{dev1.write_code('Python')}")
print(designer.create_design("쇼핑몰 앱"))
출력
=== 급여 명세서 ===
[DEV001] 김개발 - Senior Developer: 4,000,000원
[DEV002] 이코드 - Junior Developer: 3,000,000원
[DES001] 박디자인 - UI/UX Designer: 3,500,000원
[MGR001] 최매니저 - Manager (팀원 3명): 5,300,000원
총 급여: 15,800,000원
총 직원 수: 4명
최매니저의 팀:
- [DEV001] 김개발 - Senior Developer
- [DEV002] 이코드 - Junior Developer
- [DES001] 박디자인 - UI/UX Designer
김개발이(가) Python로 코드를 작성합니다
박디자인이(가) 쇼핑몰 앱의 디자인을 작성합니다
8. 상속 vs 컴포지션 (Composition)
항상 상속이 답은 아니다. "is-a" 관계일 때는 상속, "has-a" 관계일 때는 컴포지션을 사용한다.
# 상속 (is-a): 자동차는 차량이다
class Vehicle:
pass
class Car(Vehicle): # Car is a Vehicle
pass
# 컴포지션 (has-a): 자동차는 엔진을 가지고 있다
class Engine:
def start(self):
return "엔진 시동"
class Car:
def __init__(self):
self.engine = Engine() # Car has an Engine
def start(self):
return self.engine.start()
언제 컴포지션을 사용할까?
- 상속 계층이 너무 깊어질 때
- 여러 기능을 유연하게 조합해야 할 때
- "has-a" 관계가 더 명확할 때
핵심 요약
| 개념 | 설명 | 언제 사용? |
| 상속 | 부모 클래스의 기능을 물려받음 | is-a 관계, 코드 재사용 |
| 오버라이딩 | 부모 메서드를 재정의 | 동작을 변경해야 할 때 |
| super() | 부모 클래스 메서드 호출 | 부모 기능 확장 |
| 다형성 | 같은 인터페이스, 다른 동작 | 유연한 코드 설계 |
| 추상 클래스 | 구현을 강제하는 템플릿 | 인터페이스 정의 |
| 다중 상속 | 여러 부모로부터 상속 | 여러 기능 조합 |
| 컴포지션 | 객체를 포함 | has-a 관계 |
결론
상속과 다형성을 잘 활용하면
- 코드 재사용성이 높아진다
- 유지보수가 쉬워진다
- 확장 가능한 구조를 만들 수 있다
- 더 직관적이고 읽기 쉬운 코드를 작성할 수 있다
하지만 과도한 상속은 복잡도를 높일 수 있으므로, 상황에 맞게 상속과 컴포지션을 적절히 선택하는 것이 중요하다!
Reference
- Python ABC: https://docs.python.org/3/library/abc.html
- Python MRO: https://docs.python.org/3/howto/mro.html
- GeeksforGeeks - MRO: https://www.geeksforgeeks.org/python/method-resolution-order-in-python-inheritance/
- DataCamp - Inheritance: https://www.datacamp.com/tutorial/python-inheritance
- AlmaBetter: https://www.almabetter.com/bytes/tutorials/python/python-inheritance-and-polymorphism
- DataFlair: https://data-flair.training/blogs/python-multiple-inheritance/
- CoderzColumn: https://coderzcolumn.com/blogs/python/method-resolution-order-in-python-while-using-multiple-inheritance
728x90
반응형
'Launguage' 카테고리의 다른 글
| Python TypeVar와 제네릭, 제대로 알고 쓰자 (0) | 2026.01.02 |
|---|---|
| Python 예외 처리와 컨텍스트 매니저 완벽 가이드 (0) | 2025.12.19 |
| Python 클래스 데코레이터 완벽 가이드 (0) | 2025.11.21 |
| Python 매직 메서드 완벽 가이드 (0) | 2025.11.07 |
| Python 메서드의 3가지 종류: Instance, Class, Static Method 완벽 정리 (1) | 2025.10.24 |