파이썬에서 다중 상속과 함께 super() 함수 작동 방식
파이썬에서 super()
함수는 다중 상속 구조에서 메서드를 호출할 때 사용되는 중요한 도구입니다. 다중 상속이란 한 클래스가 여러 부모 클래스로부터 속성과 메서드를 상속받는 상속 방식입니다.
super()
함수는 현재 클래스의 **메소드 해결 순서(MRO)**를 고려하여 올바른 부모 클래스 메서드를 호출하도록 돕습니다. MRO는 메서드 호출 시 검색되는 클래스 순서를 정의하며, 일반적으로 다음과 같이 구성됩니다.
- 현재 클래스
- 현재 클래스의 직접 부모 클래스
- 부모 클래스 2
- ...
- 최상위 부모 클래스
만약 super()
함수 없이 다중 상속 구조에서 메서드를 직접 호출하면, 메서드 호출 순서에 따라 원하지 않는 메서드가 호출될 수 있습니다. super()
함수는 이러한 문제를 해결하고 올바른 메서드가 호출되도록 보장합니다.
super()
함수 작동 방식
super()
함수는 두 가지 형식으로 사용될 수 있습니다.
- 인수 없이 사용: 이 경우 현재 클래스의 직접 부모 클래스를 반환합니다.
- 하나의 인수와 함께 사용: 이 경우 첫 번째 인수로 전달된 객체를 사용하여 MRO에서 다음 클래스를 반환합니다. 일반적으로 이 인수는 현재 클래스 인스턴스입니다.
다음은 super()
함수 사용 예시입니다.
class Parent1:
def __init__(self, name):
self.name = name
class Parent2:
def __init__(self, age):
self.age = age
class Child(Parent1, Parent2):
def __init__(self, name, age):
super().__init__(name) # Parent1.__init__(self, name) 호출
super(Child, self).__init__(age) # Parent2.__init__(self, age) 호출
child = Child('철수', 7)
print(child.name) # '철수' 출력
print(child.age) # 7 출력
위 코드에서 super().__init__(name)
은 Parent1.__init__(self, name)
을 호출하고, super(Child, self).__init__(age)
는 Parent2.__init__(self, age)
를 호출합니다. 즉, super()
함수는 각 부모 클래스의 생성자를 올바른 순서대로 호출하도록 합니다.
다중 상속에서 super()
함수 활용
다중 상속에서 super()
함수는 다음과 같은 상황에서 유용하게 활용됩니다.
- 동일한 이름의 메서드를 가진 여러 부모 클래스:
super()
함수를 사용하여 올바른 부모 클래스 메서드를 명시적으로 호출할 수 있습니다. - 부모 클래스 메서드 재정의:
super()
함수를 사용하여 부모 클래스 메서드를 기반으로 자식 클래스 메서드를 구현할 수 있습니다. - 다이아몬드 상속 구조: 다이아몬드 상속 구조에서
super()
함수를 사용하여 메서드 호출 순서를 명확하게 제어할 수 있습니다.
결론
super()
함수는 다중 상속 구조에서 메서드를 호출할 때 필수적인 도구입니다. MRO를 이해하고 super()
함수를 올바르게 사용することで 효율적이고 명확한 다중 상속 코드를 작성할 수 있습니다.
super()
함수 활용 예시: 다이아몬드 상속 구조
다이아몬드 상속 구조는 한 클래스가 두 개의 부모 클래스로부터 상속받는 상속 방식입니다. 이 경우, 두 부모 클래스가 동일한 이름의 메서드를 가지고 있을 수 있으며, 어떤 메서드를 호출해야 하는지 명확하지 않을 수 있습니다.
class Animal:
def speak(self):
print("동물이 울다")
class Dog(Animal):
def speak(self):
print("개가 짖다")
class Cat(Animal):
def speak(self):
print("고양이가 야옹하다")
class Husky(Dog, Cat):
def speak(self):
# super()를 사용하여 부모 클래스 메서드 호출 순서 지정
super(Dog, self).speak() # Dog.speak() 호출
super(Cat, self).speak() # Cat.speak() 호출
husky = Husky()
husky.speak() # 개가 짖다, 고양이가 야옹하다 출력
위 코드에서 Husky
클래스는 Dog
클래스와 Cat
클래스로부터 상속받습니다. 두 부모 클래스 모두 speak()
메서드를 가지고 있지만, Husky
클래스는 super()
함수를 사용하여 각 부모 클래스의 speak()
메서드를 명시적으로 호출합니다.
따라서 husky.speak()
메서드를 호출하면 먼저 Dog.speak()
메서드가 호출되고, 그 다음에 Cat.speak()
메서드가 호출됩니다.
이처럼 super()
함수를 사용하면 다이아몬드 상속 구조에서 메서드 호출 순서를 명확하게 제어하고 원하는 동작을 구현할 수 있습니다.
추가 예시
다음은 super()
함수를 사용하여 부모 클래스 메서드를 재정의하는 예시입니다.
class Person:
def __init__(self, name):
self.name = name
def introduce(self):
print(f"안녕하세요, 제 이름은 {self.name}입니다.")
class Student(Person):
def __init__(self, name, major):
super().__init__(name) # Person.__init__(self, name) 호출
self.major = major
def introduce(self):
# 부모 클래스 메서드 재정의
super().introduce() # Person.introduce() 호출
print(f"저는 {self.major}을専攻하고 있습니다.")
student = Student("철수", "컴퓨터공학")
student.introduce() # 안녕하세요, 제 이름은 철수입니다. 저는 컴퓨터공학을専攻하고 있습니다. 출력
위 코드에서 Student
클래스는 Person
클래스로부터 상속받습니다. Student
클래스는 __init__()
메서드를 재정의하지 않지만, introduce()
메서드를 재정의합니다.
introduce()
메서드는 super()
함수를 사용하여 Person
클래스의 introduce()
메서드를 호출한 다음, 추가 정보를 출력합니다.
따라서 student.introduce()
메서드를 호출하면 먼저 "안녕하세요, 제 이름은 철수입니다." 라고 출력하고, 그 다음에 "저는 컴퓨터공학을専攻하고 있습니다." 라고 출력됩니다.
super()
함수 대체 방법
파이썬에서 다중 상속 구조에서 메서드를 호출할 때 super()
함수를 사용하는 것이 일반적이지만, 상황에 따라 다음과 같은 대체 방법을 사용할 수도 있습니다.
명시적 메서드 호출:
각 부모 클래스의 메서드를 직접 호출하는 방법입니다. 예를 들어, 다음과 같이 작성할 수 있습니다.
class Parent1:
def speak(self):
print("Parent1에서 말하다")
class Parent2:
def speak(self):
print("Parent2에서 말하다")
class Child(Parent1, Parent2):
def speak(self):
Parent1.speak(self) # 명시적 메서드 호출
Parent2.speak(self)
child = Child()
child.speak() # Parent1에서 말하다, Parent2에서 말하다 출력
이 방법은 간단하지만, 메서드 이름을 직접 작성해야 하기 때문에 코드가 다소 지저분해질 수 있습니다. 또한, 다이아몬드 상속 구조와 같은 복잡한 상속 구조에서는 코드 관리가 어려울 수 있습니다.
다중 상속 순서 변경:
class
선언문에서 상속 클래스를 나열하는 순서를 변경하여 원하는 메서드 호출 순서를 제어할 수 있습니다. 예를 들어, 다음과 같이 작성할 수 있습니다.
class Parent2:
def speak(self):
print("Parent2에서 말하다")
class Parent1:
def speak(self):
print("Parent1에서 말하다")
class Child(Parent2, Parent1):
def speak(self):
super().speak() # 여전히 super() 함수 사용
child = Child()
child.speak() # Parent2에서 말하다, Parent1에서 말하다 출력
이 방법은 super()
함수를 사용하지 않고도 메서드 호출 순서를 제어할 수 있지만, 상속 클래스 순서를 변경해야 하기 때문에 코드 가독성이 떨어질 수 있습니다. 또한, 상속 구조가 변경될 경우, 메서드 호출 순서가 변경될 수 있다는 문제점이 있습니다.
믹스인 클래스 사용:
믹스인 클래스는 공통 기능을 제공하는 클래스이며, 다중 상속 대신 상속받아 사용됩니다. 믹스인 클래스를 사용하면 코드 재사용성을 높일 수 있으며, 다중 상속으로 인한 복잡성을 줄일 수 있습니다.
예를 들어, 다음과 같이 믹스인 클래스를 사용하여 speak()
메서드를 정의할 수 있습니다.
class Speakable:
def speak(self):
print("말하다")
class Parent1:
pass
class Parent2:
pass
class Child(Parent1, Parent2, Speakable):
pass
child = Child()
child.speak() # 말하다 출력
이 방법은 super()
함수나 명시적 메서드 호출 없이 간단하게 메서드를 호출할 수 있지만, 모든 상황에 적용되는 것은 아닙니다. 또한, 믹스인 클래스를 너무 많이 사용하면 코드 구조가 복잡해질 수 있습니다.
결론
super()
함수는 다중 상속 구조에서 메서드를 호출할 때 가장 일반적이고 유연하게 사용할 수 있는 도구입니다. 하지만, 상황에 따라 명시적 메서드 호출, 다중 상속 순서 변경, 믹스인 클래스 사용과 같은 대체 방법을 사용することも 가능합니다.
python multiple-inheritance