15장. 객체 지향 프로그래밍-3

asda주asda·2022년 2월 1일
0

Python

목록 보기
19/31

클래스 다중 상속

다중 상속

다중 상속은 여러 기반 클래스로부터 상속을 받아서 파생 클래스를 만드는 방법이다. 형태는 다음과 같다.

class 파생클래스이름(기반클래스1, 기반클래스2):

# 코드 작성

다중 상속에는 2가지 문제점이 있다.

  • 상속받은 여러 기초 클래스에 같은 이름의 멤버가 존재할 가능성이 있다.(충돌성)
  • 하나의 클래스를 간접적으로 두 번 이상 상속받을 가능성이 있다.

아래 코드는 Person 클래스와 University 클래스를 만든 후 다중 상속으로 Undergraduate 클래스를 만들었다.


class Person:
    def greeting(self):
        print('안녕하세요.')
 
class University:
    def manage_credit(self):
        print('학점 관리')
 
 # Person 클래스와 University 클래스를 상속받았다.
class Undergraduate(Person, University):
    def study(self):
        print('공부하기')
 
james = Undergraduate()
james.greeting()         # 안녕하세요.: 기반 클래스 Person의 메서드 호출
james.manage_credit()    # 학점 관리: 기반 클래스 University의 메서드 호출
james.study()            # 공부하기: 파생 클래스 Undergraduate에 추가한 study 메서드

출력 결과:
안녕하세요.
학점 관리
공부하기

아래의 그림을 '상속 계층도' 로서 위의 코드를 나타낸다.

다이아몬드 상속

먼저 아래의 코드를 보자

class A:
    def greeting(self):
        print('안녕하세요. A입니다.') 
        
class B(A):
    def greeting(self):
        print('안녕하세요. B입니다.') 
        
class C(A):
    def greeting(self):
        print('안녕하세요. C입니다.') 
# 기반 클래스 A를 B와 C가 받고 다시 D가 B,C를 받는다.         
class D(B, C):
    pass
 
 # 메인 코드
x = D()
x.greeting()

출력 결과: 
안녕하세요. B입니다.


위의 그림은 코드의 '상속 계층도' 이다. 클래스 간의 관계가 다이아몬드 같이 생겼기에 객체지향 프로그래밍에서는 이런 상속 관계를 다이아몬드 상속이라 한다.

프로그래밍을 할 때 위와 같이 모호한 코드는 좋지 못하다. 프로그램이 어떨 때는 A를 어떨 때는 B 또는 C의 메서드를 호출한다면 큰 문제이다. 그래서 이런 다이아몬드 형태의 상속은 사용되지 않는다.

다이아몬드 상속 문제점의 해결책

파이썬에서 다이아몬드 상속의 문제점의 해결책으로 메서드 탐색 순서(Method Resolution Ordere, MRO)를 따른다. 위의 코드의 클래스 D에 메서드 mro()를 사용(클래스.__mro__)하면 메서드 탐색 순서가 나타난다.

print(D.__mro__)
(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

MRO에 따르면 D의 메소드 호출 순서는 자기 자신(D), 그리고 B, C, A 이다. 그렇기에 인스턴스 D의 greeting 호출은 B의 greeting이 호출된다.

파이썬은 다중 상속을 한다면 class D(B, C) : 의 클래스 목록 중 왼쪽에서 오른쪽 순서로 메서드를 찾는다. 그러므로 같은 메서드가 있다면 B가 우선한다.만약 상속 관계가 복잡하게 얽혀 있다면 MRO를 살펴보는 것이 편리하다.

다형성(polymorphism)

다형성은 '여러 가지 형태를 가질 수 있는 능력' 을 말하며, 아울러 다형성은 보이는 이름은 같지만 실제 모습 혹은 행위는 다른 특징을 말한다.

다형성은 크게 '형식의 다형성'과 '메서드의 다형성'으로 나눌 수 있다.
형식의 다형성은 특정 변수에 참조하는 인스턴스가 다를 수 있음을 의미한다.
그리고 메서드의 다형성은 특정 변수로 호출하는 메서드는 실제 참조하는 인스턴스에 따라 서로 다르게 정의한 메서드를 호출할 수 있음을 의미한다.

형식의 다형성의 예

# 다형성의 개념은 여러가지 형태를 가질 수 있는 능력이다.
# 보이는 실제 모습 혹은 행위는 다른 특징을 지닐 수 있다.
# 형식의 다형성, 메서드의 다형성으로 나뉠 수 있다.


class Animal:
    def __init__(self ,name, age, weight, instance):
        self.__name = name
        self.__age = age
        self.__weight = weight
        # 아래 코드는  독립적인 클래스의 인스턴스를 받는다.
        self.__instance = instance

    def show(self):
        print("이름: ",self.__name)
        print("종류: ",self.__instance.d_name)
        print("나이: ",self.__age)
        print("몸무게: ",self.__weight)
        # 아래 코드는  독립적인 클래스의 인스턴스를 받는다.
        self.__instance.sound()
        print('===========================')

class Tiger:
    d_name = '호랑이'
    def sound(self):
        print("나는 호랑이랍니다.")


class Dog:
    d_name = '개'
    def __init__(self):
        pass
    # def __init__(self):
    #     Animal.__init__('',0,0,None)
    def sound(self):
        print("나는 개랍니다.")


class Cat:
    d_name = '고양이'
    def sound(self):
        print("나는 고양이랍니다.")

if __name__ == '__main__':
    ani1 = Animal('호돌이', 80, 180, Tiger())
    ani1.show()

    ani2 = Animal('말랑이', 40, 90, Dog())
    ani2.show()

    ani3 = Animal('깜둥이', 10, 40, Cat())
    ani3.show()
    
 출력 결과:
 이름:  호돌이
종류:  호랑이
나이:  80
몸무게:  180
나는 호랑이랍니다.
===========================
이름:  말랑이
종류:  개
나이:  40
몸무게:  90
나는 개랍니다.
===========================
이름:  깜둥이
종류:  고양이
나이:  10
몸무게:  40
나는 고양이랍니다.
===========================

메서드의 다형성의 예

# 2. 메서드의 다형성
class SalesWorker:
    def __init__(self, name):
        self.__name = name
    def work(self):
        print(self.__name, '물건을 팝니다.')

class DevWorker(SalesWorker):
    def __init__(self, name):
        SalesWorker.__init__(self, name)
        self.__name = name
    def work(self):
        print(self.__name, '물건을 개발합니다.')

if __name__ == '__main__':
    worker1 = SalesWorker('David')
    worker2 = SalesWorker('옥분자')
    worker3 = SalesWorker('나카무라상')

    worker4 = DevWorker('김옥철')
    worker5 = DevWorker('은갑수')
    worker6 = DevWorker('지갑')

    workers = [worker1, worker2, worker3, worker4, worker5, worker6]
    # 인스턴스의 타입에 따라 코드의 명(메서드)은 동일하나, 실제 호출되는 work()는
    # 메서드가 달라 출력결과가 틀리다.
    for worker in workers:
        worker.work()

출력 결과:
David 물건을 팝니다.
옥분자 물건을 팝니다.
나카무라상 물건을 팝니다.

김옥철 물건을 개발합니다.
은갑수 물건을 개발합니다.
지갑 물건을 개발합니다.

추상 클래스

추상클래스

파이썬은 추상 클래스(abstract class)라는 기능을 제공한다. 추상 클래스는 메소드의 목록만 가진 클래스이며 상속 받는 클래스에서 메서드 구현을 강제하기 위해 사용한다. 또한 선언부만 존재하고 구현부는 없다.

추상 클래스를 만들려면 import로 abc 모듈을 가져와야 한다.(abc 모듈은 abstract base class의 약자이다). 그리고 클래스의 ( )(괄호) 안에 metaclass=ABCMeta를 지정하고, 메서드를 만들 때 위에 @abstractmethod를 붙여서 추상 메서드로 지정한다.

추상클래스는 인스턴스를 만들 수가 없다.그 이유는 추상 메서드가 존재하기 때문이다.그렇기에 추상메서드를 하나라도 가지고 있다면 그 클래스는 추상클래스가 되며 인스턴스를 생성할 수가 없다.

from abc import *
 
class StudentBase(metaclass=ABCMeta):
    @abstractmethod
    def study(self):
        pass
 
    @abstractmethod
    def go_to_school(self):
        pass
 
class Student(StudentBase):
    def study(self):
        print('공부하기')
 
james = Student()
james.study()

출력 결과:
Traceback (most recent call last):
  File "C:\project\class_abc_error.py", line 16, in <module>
    james = Student()
TypeError: Can't instantiate abstract class Student with abstract methods go_to_school 

위의 코드에서는 오류가 발생했다. 그 이유는 추상 클래스의 StudentBase에서는 두 개의 추상 메서드를 가지고 있고 이를 클래스 Student가 받고 있다. 그리고 메소드로는 추상 메서드 중 하나인 study 메서드만을 구현하였다. 즉 또 다른 추상 메서드 go_to_school에 대한 메서드를 구현하지 않았기에 오류가 발생한 것이다.

추상 클래스를 상속받았다면 @abstractmethod가 붙은 추상 메서드를 모두 구현해야 한다. 다음과 같이 Student 클래스에서 go_to_school() 메서드도 구현해 주도록 한다.

from abc import *
 
class StudentBase(metaclass=ABCMeta):
    @abstractmethod
    def study(self):
        pass
 
    @abstractmethod
    def go_to_school(self):
        pass
 
class Student(StudentBase):
    def study(self):
        print('공부하기')
 
    def go_to_school(self):
        print('학교가기')
 
james = Student()
james.study()
james.go_to_school()

실행 결과:
공부하기
학교가기

추상클래스의 용도

추상클래스는 상속받는 각각의 자손클래스에서 다른 내용으로 구현될 것을 예상하고 뼈대만 만드는 것이다.

0개의 댓글

관련 채용 정보