파이썬 상속 정리
상속(Inheritance)은 객체 지향 프로그래밍의 핵심 개념이다. 기존의 클래스를 기반으로 새로운 클래스를 정의하고, 속성 및 메서드를 "물려받는" 방식이다. 이를 통해 코드 재사용성을 높이고, 중복을 줄이며, 프로그램의 유지보수를 쉽게 만든다.
1. 기본 개념 및 구조
상속의 기초는 부모 클래스(기반 클래스)와 자식 클래스(파생 클래스) 간의 관계로 이루어진다. 자식 클래스는 부모 클래스의 모든 속성과 메서드를 "상속"받아 사용하며, 필요에 따라 새로운 기능을 추가하거나 기존 기능을 재정의할 수 있다.
class Animal: # 부모 클래스
def __init__(self, name):
self.name = name
def speak(self):
print(f"{self.name}이(가) 소리를 낸다.")
class Dog(Animal): # 자식 클래스
def __init__(self, name, breed):
super().__init__(name) # 부모 클래스의 __init__ 메서드 호출
self.breed = breed
def bark(self):
print(f"{self.name}이(가) 짖는다.")
이 코드에서 Animal은 부모 클래스다. 모든 동물에 대한 공통 속성(name)과 행동(speak())을 정의한다.
Dog는 자식 클래스다. Animal의 속성과 메서드를 물려받으며, 새로운 속성(breed)과 메서드(bark())를 추가했다.
2. super() 함수의 역할
super()는 자식 클래스에서 부모 클래스의 메서드를 호출할 때 사용한다. 특히 초기화 메서드(__init__())에서 부모의 속성을 초기화하는 데 유용하다.
class Parent:
def __init__(self, name):
self.name = name
print("Parent의 __init__ 호출")
class Child(Parent):
def __init__(self, name, age):
super().__init__(name) # 부모 클래스의 __init__ 호출
self.age = age
print("Child의 __init__ 호출")
child = Child("철수", 12)
출력:
Parent의 __init__ 호출
Child의 __init__ 호출
super().__init__(name)은 부모 클래스 Parent의 __init__() 메서드를 호출하여 name 속성을 초기화한다. 또한 super()는 다중 상속 시에도 올바른 부모 메서드를 호출하는 데 사용된다.
3. 메서드 오버라이딩 (Method Overriding)
메서드 오버라이딩은 부모 클래스에서 정의된 메서드를 자식 클래스에서 재정의하는 것이다. 이를 통해 자식 클래스는 부모의 기본 동작을 자신에 맞게 변경할 수 있다.
class Animal:
def speak(self):
print("동물이 소리를 낸다.")
class Cat(Animal):
def speak(self): # 부모 클래스의 speak() 메서드를 재정의
print("고양이가 야옹~")
cat = Cat()
cat.speak() # "고양이가 야옹~" 출력
Animal 클래스의 speak() 메서드는 모든 동물에 대해 기본 동작을 정의한다. Cat 클래스는 speak()를 오버라이딩하여 고유한 행동을 정의했다.
4. 다중 상속 (Multiple Inheritance)
파이썬은 다중 상속을 지원한다. 즉, 하나의 자식 클래스가 여러 부모 클래스를 상속받을 수 있다. 다중 상속은 강력한 기능이지만 복잡성을 유발할 수 있으므로 주의가 필요하다.
class Animal:
def speak(self):
print("동물이 소리를 낸다.")
class Pet:
def be_cute(self):
print("애완동물이 귀엽다.")
class Dog(Animal, Pet):
pass
dog = Dog()
dog.speak() # Animal 클래스의 메서드 호출
dog.be_cute() # Pet 클래스의 메서드 호출
Dog 클래스는 Animal과 Pet 두 부모 클래스를 상속받는다. 자식 클래스는 두 부모 클래스의 속성과 메서드를 모두 사용할 수 있다.
단, 다중 상속을 사용할 때 충돌이 발생할 수 있으므로, 상속 순서(MRO, Method Resolution Order)에 주의해야 한다.
5. 상속의 장점과 특징
- 코드 중복 감소: 부모 클래스에서 공통된 속성과 메서드를 정의하면, 자식 클래스는 이를 재사용하여 불필요한 중복을 줄일 수 있다.
- 확장성: 자식 클래스에서 새로운 기능을 추가하거나 부모의 메서드를 재정의하여 동작을 변경할 수 있다.
- 유지보수 용이: 부모 클래스에서 변경 사항을 적용하면 이를 상속받은 모든 자식 클래스에 자동으로 반영된다.
6. 실용적인 예제
다양한 동물 클래스를 상속을 통해 구현해보자.
class Animal:
def __init__(self, name):
self.name = name
def sound(self):
pass # 구체적인 동작은 자식 클래스에서 정의한다.
class Dog(Animal):
def sound(self):
return "멍멍!"
class Cat(Animal):
def sound(self):
return "야옹!"
animals = [Dog("바둑이"), Cat("나비")]
for animal in animals:
print(f"{animal.name}이(가) {animal.sound()}")
출력:
바둑이이(가) 멍멍!
나비이(가) 야옹!
Animal은 모든 동물의 공통된 속성을 정의한다. Dog와 Cat은 Animal을 상속받아 자신만의 sound() 메서드를 구현한다.
이 구조는 확장성이 뛰어나며, 새로운 동물 클래스를 쉽게 추가할 수 있다.
추가 팁
- 추상 클래스와 인터페이스: 모든 메서드가 반드시 재정의되어야 하는 경우 abc 모듈을 사용하여 추상 클래스를 만들 수 있다.
- 다중 상속 충돌 방지: super()와 MRO를 활용하여 다중 상속 시 발생할 수 있는 메서드 충돌 문제를 해결할 수 있다.
정리
상속은 파이썬에서 매우 강력한 도구다. 잘 활용하면 코드 중복을 줄이고 유지보수를 더 쉽게 할 수 있다. super(), 메서드 오버라이딩, 다중 상속 등의 기능을 이해하고 활용하여 유연하고 강력한 객체 지향 코드를 작성할 수 있다.