[파이썬] 클래스 상속연결하기(Method Overriding)

반응형
    반응형

    클래스 연결

    메서드 오버라이딩(Method Overriding)은 객체 지향 프로그래밍에서 하위 클래스가 상위 클래스로부터 상속받은 메서드를 재정의하는 개념입니다. 이는 상속 관계에 있는 클래스 간에 동일한 메서드 이름을 사용하면서 각 클래스에서 특정 메서드의 동작을 변경하고자 할 때 사용됩니다.

    메서드 오버라이딩의 주요 특징은 다음과 같습니다:

    1. 상속 관계 필요: 메서드 오버라이딩은 부모 클래스와 자식 클래스 간의 상속 관계에서만 발생합니다.
    2. 메서드 시그니처 동일: 오버라이딩되는 메서드는 메서드 시그니처(이름, 매개변수 형식, 반환 형식)가 부모 클래스의 메서드와 동일해야 합니다.
    3. 동적 바인딩: 어떤 메서드가 호출될지는 객체의 실제 타입에 따라 동적으로 결정됩니다. 즉, 실행 시간에 객체의 실제 타입을 고려하여 오버라이딩된 메서드가 호출됩니다.

    간단한 예제를 통해 메서드 오버라이딩을 살펴보겠습니다.

    class Animal:
        def make_sound(self):
            print("Generic animal sound")
    
    class Dog(Animal):
        def make_sound(self):
            print("Bark, bark!")
    
    class Cat(Animal):
        def make_sound(self):
            print("Meow, meow!")
    
    # 메서드 오버라이딩 사용
    dog = Dog()
    dog.make_sound()  # "Bark, bark!"
    
    cat = Cat()
    cat.make_sound()  # "Meow, meow!"

     

    이 예제에서 DogCat 클래스는 Animal 클래스를 상속받습니다. 각각의 하위 클래스에서 make_sound 메서드를 오버라이딩하여 동물의 소리를 특화시켰습니다. 이렇게 하면 같은 메서드 이름을 사용하면서도 다양한 하위 클래스에서 메서드의 동작을 다르게 정의할 수 있습니다.

    사실 상속 없이도 가능

    위의 예제는 확실히 상속이 일어났습니다. 그렇기 때문에 Animal()이 정의 되어있는 상태에서만 일어납니다. 그렇지만 저런 상속은 필요없습니다. 안해도 똑같이 됩니다.

    class Dog():
        def speak(self):
            print("강아지가 짖습니다.")
    
    dog = Dog()
    dog.speak()

    명령을 하는데 아무 하자가 없습니다. 그렇다면 도대체 상속은 언제 해야할까요?

    상속이 필요한 경우

    상속이 필요한 경우는 크게 4가지로 나눠집니다.

    1. 계층 구조 필요

    상속을 이용하면 계층 구조를 만들 수 있습니다. 계층구조가 되면 코드 이해와 유지보수가 쉬워집니다. 위의 예제에서 상속이 된 경우는 누군가가 보면 상속관계를 그려낼 수 있기에 클래스간 어떤 것들이 주고받는지알 수 있게 됩니다.

    2. 다형성이 필요한 경우

    클래스 상속은 다형성을 지원합니다. 부모 클래스 타입으로 선언된 변수는 자식 클래스의 객체를 가리킬 수 있습니다. 이는 유연성을 제공하며, 동일한 메소드 호출을 통해 서로 다른 하위 클래스의 특정 동작을 활용할 수 있습니다.

    3. 추상화와 공통된 인터페이스 필요

    부모 클래스에서는 추상적으로 메소드를 만들고 자식 클래스에서 이를 구현함으로써 추상화와 일관된 인터페이스를 유지할 수 있습니다. 이는 코드의 일관성을 높이고 개발자에게 특정 메소드의 구현을 강제함으로써 코드의 예측 가능성을 높입니다.

    4. 코드 재사용과 중복 제거

    클래스 상속을 통해 부모 클래스의 속성과 메소드를 자식 클래스에서 재사용할 수 있습니다. 이는 중복 코드를 방지하고 코드의 재사용성을 높일 수 있습니다.

    예제

    서로 데이터를 주고받는 상속을 구현해보겠습니다.

    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)
            self.breed = breed
    
        def bark(self):
            print(f"{self.name}이(가) {self.breed} 품종의 강아지가 짖습니다.")
    
    class Cat(Animal):
        def __init__(self, name, color):
            super().__init__(name)
            self.color = color
    
        def meow(self):
            print(f"{self.color} 고양이 {self.name}이(가) 야옹합니다.")
    
    # 객체 생성
    animal = Animal("동물")
    dog = Dog("멍멍이", "시바견")
    cat = Cat("야옹이", "흰색")
    
    # 메소드 호출
    animal.speak()  # "동물이 소리를 냅니다."
    dog.speak()     # "멍멍이이(가) 소리를 냅니다."
    dog.bark()      # "멍멍이이(가) 시바견 품종의 강아지가 짖습니다."
    cat.speak()     # "야옹이이(가) 소리를 냅니다."
    cat.meow()      # "흰색 고양이 야옹이이(가) 야옹합니다."

    Dog에는 speak()메쏘드가 없지만 dog.speak()를 명령하면 Animal 클래스에 있는 speak()를 가져다 씁니다.
    Animal 클래스는 자식 클래스인 Dog의 Name 을 가져와서 speak()를 이행하게 됩니다.

    Animal 클래스의 speak() 메쏘드에 어느것이든 들어맞을 수 있게 조정을 해주어 자식 클래스에 있는 어떤 값이 입력되든 쓸 수 있게 해주면 좀 더 편리하게 코딩작업을 할 수 있습니다.

    마치며

    메소드 오버라이딩에 대해서 알아보았습니다. 현재 예제는 간단하게 보였지만 실제 개발에서는 복잡한 코드를 하게 되니 상속을 쓰는 게 더 편해질지도 모릅니다. 부모 자식 클래스간의 소통이 어떻게 이뤄지는게 효율적인지 고민하셔서 유용하게 활용하시기 바랍니다.

    댓글

    Designed by JB FACTORY

    ....