파이썬의 객체지향 프로그래밍에서 상속과 다형성은 코드의 재사용성과 유연성을 높이는 중요한 개념입니다. 상속은 기존 클래스를 확장하여 새로운 클래스를 만드는 기능이며, 다형성은 동일한 메서드 이름이 클래스에 따라 다르게 동작하는 성질을 의미합니다.
1. 상속(Inheritance)
상속은 기존 클래스(부모 클래스, 슈퍼클래스)를 확장하여 새로운 클래스(자식 클래스, 서브클래스)를 정의하는 것입니다. 상속을 통해 기존 클래스의 속성과 메서드를 재사용하면서, 새로운 기능을 추가하거나 기존 기능을 변경할 수 있습니다.
기본 구조
class ParentClass:
# 부모 클래스의 속성과 메서드
pass
class ChildClass(ParentClass):
# 자식 클래스는 부모 클래스의 속성과 메서드를 상속받음
pass
2. 예제: 상속을 통한 클래스 확장
다음 예제에서 Animal 클래스를 부모 클래스로 정의하고, 이를 상속받아 Dog와 Cat 클래스를 만듭니다.
class Animal:
def __init__(self, name):
self.name = name
def speak(self):
print("동물이 소리를 냅니다.")
class Dog(Animal):
def speak(self):
print(f"{self.name}가 멍멍 소리를 냅니다.")
class Cat(Animal):
def speak(self):
print(f"{self.name}가 야옹 소리를 냅니다.")
dog = Dog("바둑이")
cat = Cat("나비")
dog.speak() # 결과: 바둑이가 멍멍 소리를 냅니다.
cat.speak() # 결과: 나비가 야옹 소리를 냅니다.
설명: Animal 클래스는 기본적인 속성과 메서드를 정의하고, Dog와 Cat 클래스는 Animal을 상속받아 speak() 메서드를 각각의 동물에 맞게 오버라이딩하여 동작을 다르게 합니다.
3. super() 함수
super() 함수는 부모 클래스의 메서드를 호출할 때 사용됩니다. 상속받은 자식 클래스에서 부모 클래스의 초기화 메서드(__init__)나 다른 메서드를 호출할 때 주로 사용됩니다.
class Animal:
def __init__(self, name):
self.name = name
class Dog(Animal):
def __init__(self, name, breed):
super().__init__(name) # 부모 클래스의 __init__ 호출
self.breed = breed
dog = Dog("바둑이", "진돗개")
print(dog.name) # 결과: 바둑이
print(dog.breed) # 결과: 진돗개
설명: Dog 클래스의 __init__ 메서드에서 super().__init__(name)을 사용해 부모 클래스의 __init__ 메서드를 호출하여 name을 초기화합니다. 이후 breed 속성은 Dog 클래스에 새로 추가됩니다.
4. 메서드 오버라이딩 (Method Overriding)
메서드 오버라이딩은 자식 클래스에서 부모 클래스의 메서드를 재정의하는 것입니다. 이를 통해 부모 클래스와 동일한 이름의 메서드를 자식 클래스에 맞게 구현할 수 있습니다.
class Animal:
def speak(self):
print("동물이 소리를 냅니다.")
class Dog(Animal):
def speak(self):
print("멍멍!")
class Cat(Animal):
def speak(self):
print("야옹!")
animals = [Dog(), Cat()]
for animal in animals:
animal.speak()
설명: Dog와 Cat 클래스는 부모 클래스인 Animal의 speak() 메서드를 각각의 동물에 맞게 오버라이딩하여 동작을 다르게 합니다. 반복문에서 각 인스턴스의 speak() 메서드가 호출되면, 자식 클래스에서 정의한 메서드가 실행됩니다.
5. 다중 상속 (Multiple Inheritance)
파이썬은 하나의 클래스가 둘 이상의 부모 클래스를 상속받을 수 있습니다. 다중 상속은 여러 부모 클래스의 기능을 결합하여 사용할 때 유용하지만, 복잡한 구조로 인해 혼란을 줄 수 있으므로 신중히 사용해야 합니다.
class Animal:
def eat(self):
print("음식을 먹습니다.")
class Mammal:
def give_birth(self):
print("새끼를 낳습니다.")
class Dog(Animal, Mammal):
def bark(self):
print("멍멍!")
dog = Dog()
dog.eat() # 결과: 음식을 먹습니다.
dog.give_birth() # 결과: 새끼를 낳습니다.
dog.bark() # 결과: 멍멍!
설명: Dog 클래스는 Animal과 Mammal 클래스를 동시에 상속받아, 두 부모 클래스의 기능을 모두 사용할 수 있습니다.
6. 다형성 (Polymorphism)
다형성은 같은 메서드가 다양한 방식으로 동작하도록 하는 개념입니다. 예를 들어, Animal 클래스를 상속받는 Dog와 Cat 클래스는 동일한 speak() 메서드를 가질 수 있지만, 각 클래스의 speak() 메서드는 서로 다른 방식으로 동작할 수 있습니다. 다형성은 객체의 타입에 관계없이 동일한 메서드를 호출할 수 있게 합니다.
class Animal:
def speak(self):
pass # 부모 클래스에서는 동작을 정의하지 않음
class Dog(Animal):
def speak(self):
print("멍멍!")
class Cat(Animal):
def speak(self):
print("야옹!")
def make_sound(animal):
animal.speak()
dog = Dog()
cat = Cat()
make_sound(dog) # 결과: 멍멍!
make_sound(cat) # 결과: 야옹!
설명: make_sound() 함수는 Animal 타입의 객체를 인자로 받아 speak() 메서드를 호출합니다. Dog와 Cat 클래스는 각각 자신에게 맞는 speak() 메서드를 정의하고, 함수는 인자의 실제 클래스에 따라 알맞은 speak() 메서드를 호출합니다. 이를 통해 코드가 더 유연하고 재사용 가능하게 됩니다.
7. 추상 클래스와 다형성 구현
추상 클래스는 메서드의 구체적인 구현 없이 메서드 이름만 정의하는 클래스입니다. 파이썬에서는 abc 모듈의 ABC 클래스와 abstractmethod 데코레이터를 사용해 추상 클래스를 정의할 수 있습니다. 추상 클래스는 다형성을 구현할 때 유용하게 사용할 수 있습니다.
from abc import ABC, abstractmethod
class Animal(ABC):
@abstractmethod
def speak(self):
pass
class Dog(Animal):
def speak(self):
print("멍멍!")
class Cat(Animal):
def speak(self):
print("야옹!")
animals = [Dog(), Cat()]
for animal in animals:
animal.speak()
설명: Animal 클래스는 추상 클래스로, speak() 메서드는 추상 메서드로 정의되어 있습니다. Dog와 Cat 클래스는 Animal을 상속받고, 각 클래스에서 speak() 메서드를 구체적으로 구현해야 합니다. 추상 클래스는 상속받은 클래스가 반드시 특정 메서드를 구현하도록 강제할 수 있습니다.