안녕하세요! 지난 시간에는 객체지향 프로그래밍(OOP)의 핵심 원칙인 상속(Inheritance)과 다형성(Polymorphism)에 대해 알아보았습니다. 자식 클래스가 부모 클래스의 속성과 메서드를 물려받고, 다양한 객체들이 동일한 이름의 메서드에 대해 각자의 방식으로 동작하는 것을 배웠죠!
이번 시간에는 다형성을 구현하는 주요 방법이자, 상속에서 매우 중요한 개념인 **오버라이딩(Overriding)**과, 부모 클래스의 기능을 자식 클래스에서 호출할 때 사용되는 특별한 함수 **super()**에 대해 더 깊이 알아보겠습니다.
Part 1: 오버라이딩(Overriding) - 부모의 메서드를 자식에서 재정의하기
오버라이딩은 자식 클래스가 부모 클래스로부터 물려받은 메서드와 동일한 이름으로 메서드를 다시 정의(재정의)하는 것을 의미합니다. 이렇게 하면 자식 클래스 객체가 해당 메서드를 호출했을 때, 부모의 메서드 대신 자식 클래스에서 재정의된 메서드가 실행됩니다.
1. 오버라이딩의 목적
- 다형성 구현: 다양한 타입의 객체가 동일한 메서드 이름에 대해 각자의 고유한 동작을 수행하도록 합니다. (예: Animal의 speak()를 Dog와 Cat이 다르게 구현)
- 특정 기능의 맞춤화: 부모 클래스의 일반적인 동작을 자식 클래스의 특성에 맞게 변경해야 할 때 사용합니다.
- 기존 기능의 확장: 부모의 기능을 그대로 사용하면서 추가적인 작업을 수행해야 할 때, 오버라이딩된 메서드 내부에서 부모의 메서드를 호출하고(super()) 추가 로직을 구현합니다.
2. 오버라이딩 문법
- 부모 클래스의 메서드와 **정확히 동일한 이름, 동일한 매개변수 개수(self 포함)**로 자식 클래스에서 메서드를 정의합니다.
예시: Vehicle과 Car 클래스에서 drive() 메서드 오버라이딩
# 파일 이름: overriding_example.py
# 부모 클래스
class Vehicle:
def __init__(self, brand):
self.brand = brand
print(f"{self.brand} 차량이 생성되었습니다.")
def drive(self):
print(f"{self.brand} 차량이 움직이기 시작합니다.")
def stop(self):
print(f"{self.brand} 차량이 멈춥니다.")
# 자식 클래스 (Vehicle 상속)
class Car(Vehicle):
def __init__(self, brand, model):
super().__init__(brand) # 부모 생성자 호출
self.model = model
print(f"{self.brand}의 {self.model} (자동차)가 생성되었습니다.")
# drive 메서드 오버라이딩 (부모와 동일한 이름과 매개변수)
def drive(self):
print(f"{self.brand}의 {self.model}이(가) 도로를 달립니다.")
# 객체 생성
generic_vehicle = Vehicle("일반 차량")
my_car = Car("현대", "쏘나타")
print("\n--- 드라이브 테스트 ---")
generic_vehicle.drive() # Vehicle 클래스의 drive() 호출
my_car.drive() # Car 클래스에서 오버라이딩된 drive() 호출
print("\n--- 정지 테스트 (오버라이딩 안됨) ---")
generic_vehicle.stop() # Vehicle 클래스의 stop() 호출
my_car.stop() # Vehicle 클래스의 stop() 호출 (Car에서 오버라이딩 안했으므로)
[VS Code 터미널 출력]

Part 2: super() 함수 - 부모 클래스의 기능 호출하기
super() 함수는 자식 클래스에서 부모 클래스의 메서드나 생성자에 접근하여 호출할 때 사용됩니다. 특히 오버라이딩된 메서드나 생성자 내부에서 부모의 원래 기능을 사용하고 싶을 때 매우 유용합니다.
1. super()의 주요 사용처
- 생성자 호출: 자식 클래스의 __init__ 메서드 내에서 super().__init__(...)를 호출하여 부모 클래스의 속성들을 초기화합니다. (위 상속 예시에서 이미 사용했습니다!)
- 오버라이딩된 부모 메서드 호출: 자식 클래스에서 메서드를 오버라이딩했지만, 부모의 원래 기능도 함께 수행하고 싶을 때 super().메서드이름(...)을 호출합니다.
2. super() 사용법
# 생성자 호출
super().__init__(매개변수들)
# 메서드 호출
super().부모메서드이름(매개변수들)
예시: super()를 이용한 생성자 및 오버라이딩된 메서드 호출
# 파일 이름: super_example.py
class Animal:
def __init__(self, name):
self.name = name
print(f"Animal {self.name}이(가) 생성되었습니다.")
def make_sound(self):
print(f"{self.name}이(가) 어떤 소리를 냅니다.")
class Dog(Animal):
def __init__(self, name, breed):
# 1. super()로 부모 클래스의 생성자 호출
super().__init__(name) # Animal.__init__(self, name)과 동일
self.breed = breed
print(f"Dog {self.name} ({self.breed})이(가) 생성되었습니다.")
# make_sound 메서드 오버라이딩
def make_sound(self):
# 2. super()로 오버라이딩된 부모 메서드 호출
super().make_sound() # Animal.make_sound(self)와 동일
print(f"{self.name}이(가) 멍멍 짖습니다.")
# 객체 생성
my_dog = Dog("바둑이", "진돗개")
print("\n--- 소리 내기 테스트 ---")
my_dog.make_sound()
- super().__init__(name): Dog 객체를 생성할 때, Animal 클래스의 __init__ 메서드도 호출하여 self.name 속성을 초기화하도록 합니다.
- super().make_sound(): Dog 클래스의 make_sound 메서드 내부에서, 먼저 부모 클래스인 Animal의 make_sound 기능을 실행한 다음, Dog 고유의 "멍멍 짖습니다"라는 동작을 추가합니다.
[VS Code 터미널 출력]

Part 3: 오버라이딩과 super()의 중요성
- 코드의 재사용 및 확장: 부모 클래스의 공통된 기능을 그대로 유지하면서, 자식 클래스에서 특정 부분만 다르게 또는 추가적으로 동작하도록 만들 수 있습니다.
- 유지보수 용이: 부모 클래스의 코드를 직접 수정하지 않고도 자식 클래스에서 필요한 동작을 변경할 수 있습니다.
- 캡슐화 유지: 자식 클래스가 부모 클래스의 특정 메서드를 호출할 때, super()를 통해 명시적으로 호출함으로써 부모 클래스의 내부 구현에 대한 의존성을 낮춥니다.
- 협업: 여러 개발자가 함께 작업할 때, 역할 분담과 코드의 일관성을 유지하는 데 도움이 됩니다.
마무리하며
이번 시간에는 객체지향 프로그래밍에서 매우 중요하게 사용되는 **오버라이딩(Overriding)**과 super() 함수에 대해 자세히 알아보았습니다.
- 오버라이딩: 자식 클래스에서 부모 클래스의 메서드를 동일한 이름으로 재정의하여, 자식 객체 호출 시 재정의된 메서드가 실행되도록 하는 것.
- super(): 자식 클래스에서 부모 클래스의 생성자(__init__)나 오버라이딩된 메서드를 호출할 때 사용되는 함수. 이를 통해 부모의 기능을 확장하거나 재사용할 수 있습니다.
이 두 가지 개념은 상속과 다형성을 더욱 효과적으로 활용하고, 코드를 유연하며 확장 가능하게 만드는 데 필수적인 도구입니다.
다음 포스팅에서는 객체지향 프로그래밍의 또 다른 중요한 원칙인 **캡슐화(Encapsulation)**와 관련된 접근 제한자 개념에 대해 알아보겠습니다.
궁금한 점이 있다면 언제든지 질문해주세요! 다음 포스팅에서 만나요!
'Python' 카테고리의 다른 글
7-1. 리스트/딕셔너리 컴프리헨션 심화 (0) | 2025.07.02 |
---|---|
6-7. 캡슐화와 접근 제한자 개념 (0) | 2025.07.02 |
6-5. 상속과 다형성 (0) | 2025.07.01 |
6-2. 생성자(__init__)와 인스턴스 변수 (0) | 2025.06.29 |
5-5. raise와 사용자 정의 예외 (0) | 2025.06.29 |