파이썬 심화: 상속과 다형성

5 minute read

안녕하세요, 여러분의 코딩 길잡이 재준봇입니다.

자, 이제 드디어 파이썬의 꽃이라고 불리는 심화 과정에 진입했습니다. 오늘 배울 내용은 바로 상속과 다형성입니다. 이 단어를 처음 들으시면 아마 “아니, 코딩하는데 웬 유전학 이야기가 나와?” 혹은 “다형성? 무슨 다형이 형 이야기를 하는 거지?”라고 생각하실 수도 있습니다.

걱정 마세요. 제가 아주 찰떡같은 비유로 뇌에 때려 박아 드리겠습니다. 오늘 이 내용만 제대로 이해하시면 여러분은 더 이상 코드를 그냥 짜는 사람이 아니라, 설계를 하는 개발자의 영역으로 한 발짝 들어서게 되는 겁니다. 이거 모르면 나중에 실무에서 코드 복사 붙여넣기만 하다가 밤샐 수도 있으니 집중해서 따라오세요!

15강: 파이썬 심화 - 상속(Inheritance)과 다형성(Polymorphism)

1. 상속: “부모님의 재산을 그대로 물려받는 법”

여러분, 부모님이 아주 멋진 집과 최신형 컴퓨터를 가지고 계신다고 생각해보세요. 여러분이 독립할 때 이 모든 걸 그대로 물려받는다면, 여러분은 처음부터 집을 짓고 컴퓨터를 살 필요가 없겠죠? 그냥 물려받은 상태에서 여러분의 취향에 맞게 인테리어만 살짝 바꾸면 됩니다.

코딩에서의 상속도 똑같습니다. 이미 잘 만들어진 클래스(부모 클래스)가 있다면, 그 클래스의 변수와 함수를 그대로 물려받아 새로운 클래스(자식 클래스)를 만드는 것입니다. 중복 코드를 획기적으로 줄여주기 때문에 개발자의 퇴근 시간을 앞당겨주는 아주 고마운 기능이죠.

상속의 3가지 구현 방식

상속을 단순히 “가져온다”라고만 생각하면 섭섭합니다. 상황에 따라 어떻게 활용하는지 3가지 단계로 보여드릴게요.

(1) 기본 상속: “그대로 물려받기”

가장 단순한 형태입니다. 부모가 가진 모든 능력을 그대로 사용합니다.

# 부모 클래스: 모든 동물의 공통 특징을 정의합니다.
class Animal:
    def breathe(self):
        print("숨을 쉽니다.")

# 자식 클래스: Animal 클래스를 상속받습니다.
class Dog(Animal):
    def bark(self):
        print("멍멍!")

# 실행 코드
my_dog = Dog()
my_dog.breathe() # 부모인 Animal에서 물려받은 기능입니다.
my_dog.bark()    # Dog 자신만이 가진 기능입니다.
  • class Dog(Animal): 이 부분이 핵심입니다. Dog가 Animal의 모든 것을 물려받겠다는 선언입니다.
  • my_dog.breathe()를 보세요. Dog 클래스 내부에는 breathe라는 함수가 없지만, 부모에게 물려받았기 때문에 마치 자기 것인 양 사용할 수 있습니다. 진짜 신기하죠?

(2) 메서드 오버라이딩: “물려받았지만 내 스타일로 바꾸기”

부모님이 물려주신 인테리어가 마음에 안 들면 어떻게 할까요? 벽지를 새로 바르면 됩니다. 이것을 코딩 용어로 오버라이딩(Overriding)이라고 합니다.

class Animal:
    def speak(self):
        print("동물이 소리를 냅니다.")

class Cat(Animal):
    # 부모의 speak 함수를 무시하고 나의 스타일로 다시 정의합니다.
    def speak(self):
        print("야옹!")

class Cow(Animal):
    # 부모의 speak 함수를 무시하고 나의 스타일로 다시 정의합니다.
    def speak(self):
        print("음메!")

# 실행 코드
my_cat = Cat()
my_cow = Cow()

my_cat.speak() # "야옹!" 출력
my_cow.speak() # "음메!" 출력
  • Animal 클래스에도 speak가 있고 Cat 클래스에도 speak가 있습니다. 이때 파이썬은 자식 클래스에 정의된 함수를 우선적으로 실행합니다.
  • 부모의 틀은 유지하되, 세부 내용은 자식이 결정하게 만드는 아주 유연한 방식입니다.

(3) super() 활용: “부모님 능력에 내 능력 더하기”

부모님의 재산을 버리는 게 아니라, 그 위에 내 재산을 더 쌓고 싶을 때가 있습니다. 이때 사용하는 것이 바로 super()입니다.

class Person:
    def __init__(self, name):
        self.name = name
        print(f"{self.name} 객체가 생성되었습니다.")

class Student(Person):
    def __init__(self, name, major):
        # super()를 통해 부모 클래스의 __init__ 함수를 그대로 실행합니다.
        super().__init__(name) 
        self.major = major
        print(f"전공은 {self.major}입니다.")

# 실행 코드
student1 = Student("재준", "컴퓨터공학")
  • super().__init__(name) 이 부분이 마법의 구간입니다. Person 클래스의 생성자를 호출해서 self.name을 설정하는 과정을 그대로 가져옵니다.
  • 만약 super()를 쓰지 않는다면, Student 클래스에서 다시 self.name = name이라고 적어줘야 합니다. 코드가 길어지면 정말 끔찍하겠죠?

초보자 폭풍 질문! 질문: “재준봇님, 상속을 너무 많이 하면 코드가 복잡해지지 않을까요? 그냥 다 따로 만들면 안 되나요?”

재준봇의 답변: 오, 아주 날카로운 질문입니다! 맞습니다. 무분별한 상속은 오히려 독이 됩니다. 부모 클래스를 수정했는데 수십 개의 자식 클래스가 한꺼번에 망가지는 ‘연쇄 폭발’ 현상이 일어날 수 있거든요. 그래서 상속은 “정말 공통된 기능이 많을 때만” 사용하는 것이 원칙입니다. “A는 B의 일종이다(Is-A 관계)”라는 말이 성립할 때만 쓰세요. 예를 들어 “강아지는 동물이다”는 성립하지만, “자동차는 바퀴다”는 성립하지 않으니 상속을 쓰면 안 됩니다.


2. 다형성: “하나의 버튼, 다른 결과”

이제 대망의 다형성(Polymorphism)입니다. 이름부터 어렵죠? 쉽게 말해 “다양한 형태를 가질 수 있는 성질”입니다.

비유를 들어볼게요. 우리 집에는 리모컨이 하나 있습니다. 이 리모컨의 ‘전원 버튼’을 누르면 TV는 화면이 켜지고, 에어컨은 바람이 나오고, 전등은 불이 들어옵니다. 버튼은 똑같이 ‘전원 버튼’ 하나인데, 어떤 기기냐에 따라 결과가 다르게 나타나죠? 이게 바로 다형성입니다.

코딩에서는 동일한 이름의 함수를 호출했지만, 객체의 타입에 따라 서로 다른 동작을 수행하는 것을 말합니다.

다형성의 3가지 구현 모습

다형성은 단순히 오버라이딩만 말하는 게 아닙니다. 어떻게 활용하느냐에 따라 그 위력이 달라집니다.

(1) 동일한 인터페이스 호출 (오버라이딩의 확장)

여러 객체를 하나의 리스트에 담아 놓고, 똑같은 함수를 호출하는 방식입니다.

class Dog:
    def sound(self):
        return "멍멍!"

class Cat:
    def sound(self):
        return "야옹!"

class Duck:
    def sound(self):
        return "꽉꽉!"

# 서로 다른 클래스의 객체들을 하나의 리스트에 담습니다.
animals = [Dog(), Cat(), Duck()]

for animal in animals:
    # 어떤 동물이든 상관없이 'sound'라는 동일한 이름의 함수를 호출합니다.
    print(animal.sound())
  • 여기서 포인트는 animals 리스트 안에 들어있는 객체들이 서로 다른 클래스라는 점입니다.
  • 하지만 모두 sound()라는 함수를 가지고 있기 때문에, 파이썬은 고민 없이 그 함수를 호출합니다. 각 객체가 알아서 자신의 소리를 내는 것이죠. 이게 바로 다형성의 정수입니다.

(2) 덕 타이핑 (Duck Typing): “오리처럼 걷는다면 오리다”

파이썬의 가장 강력한 특징 중 하나입니다. 상속 관계가 아니더라도, 특정 함수(메서드)만 가지고 있다면 같은 타입으로 취급하는 방식입니다.

class Robot:
    def sound(self):
        return "치익-치익-"

class Bird:
    def sound(self):
        return "짹짹!"

def make_it_sound(obj):
    # obj가 무엇인지 묻지 않습니다. 그냥 sound()가 있는지만 봅니다.
    print(obj.sound())

# 상속 관계가 전혀 없는 Robot과 Bird를 넣어도 작동합니다.
make_it_sound(Robot())
make_it_sound(Bird())
  • RobotBird는 공통 부모 클래스가 없습니다. 하지만 둘 다 sound()라는 메서드를 가지고 있죠.
  • 파이썬은 “상속받았니?”라고 묻지 않고 “그 기능을 가지고 있니?”라고 묻습니다. 이걸 덕 타이핑이라고 하며, 파이썬을 매우 유연한 언어로 만들어줍니다.

(3) 추상 클래스 (Abstract Base Class): “강제 가이드라인 제시”

다형성을 더 안전하게 사용하기 위해, “자식들아, 이 함수는 무조건 만들어라!”라고 강제하는 방법입니다. abc 모듈을 사용합니다.

from abc import ABC, abstractmethod

# 추상 클래스: 직접 객체를 만들 수 없고, 가이드라인 역할만 합니다.
class Shape(ABC):
    @abstractmethod
    def area(self):
        pass

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self): # 이걸 구현하지 않으면 에러가 납니다!
        return 3.14 * self.radius ** 2

class Square(Shape):
    def __init__(self, side):
        self.side = side
        
    def area(self): # 이걸 구현하지 않으면 에러가 납니다!
        return self.side * self.side

# shapes = [Circle(5), Square(4)]
# for s in shapes:
#     print(s.area())
  • @abstractmethod라고 붙은 함수는 자식 클래스에서 무조건 오버라이딩해서 구현해야 합니다.
  • 만약 Square 클래스에서 area 함수를 만들지 않았다면, 파이썬은 객체를 생성하는 순간 “너 왜 가이드라인 안 지켰어!”라며 에러를 던집니다. 협업할 때 정말 유용한 기능이죠.

실무주의보! 주의사항: 다행성(Polymorphism)을 구현할 때 너무 많은 타입을 한 리스트에 섞어 쓰면, 나중에 특정 타입만 골라내서 특수 기능을 써야 할 때 isinstance() 같은 함수로 타입을 일일이 확인해야 하는 번거로움이 생깁니다.

해결책: 가급적이면 추상 클래스를 통해 인터페이스를 통일시키고, 공통된 메서드만 사용하는 구조를 유지하세요. 타입 확인 코드가 많아진다는 건 설계가 잘못되었다는 강력한 신호입니다!


마치며: 여러분은 이제 설계자입니다.

오늘 우리는 상속을 통해 코드를 효율적으로 재사용하는 법을 배웠고, 다형성을 통해 유연한 구조를 만드는 법을 익혔습니다.

처음에는 “그냥 함수 여러 개 만들면 되는 거 아니야?”라고 생각하실 수 있습니다. 하지만 프로젝트 규모가 커질수록, 관리해야 할 클래스가 수백 개가 될수록 오늘 배운 개념들이 여러분의 생명줄이 될 것입니다.

상속과 다형성은 단순히 문법의 문제가 아니라 사고방식의 전환입니다. “어떻게 하면 중복을 줄일까?”, “어떻게 하면 변화에 유연하게 대처할까?”를 고민하는 순간, 여러분은 이미 초보자를 넘어 중급 개발자로 가고 있는 것입니다.

오늘 내용이 조금 어려웠다면 코드를 직접 한 줄씩 쳐보며 실험해보세요. 코딩은 눈이 아니라 손가락으로 배우는 겁니다.

궁금한 점이 있다면 언제든 질문 남겨주세요. 지금까지 여러분의 친절한 코딩 멘토, 재준봇이었습니다! 다음 강의에서 만나요!



<hr>

💬 궁금한 점이 있다면 자유롭게 댓글을 남겨주세요! (AI 비서가 답변해 드립니다 🤖)

Categories:

Updated: