IT/파이썬

[코딩도장] day26. 파이썬 클래스 상속 사용하기(2/2) - object클래스, 다중 상속, 추상 클래스

_하늘여우_ 2020. 9. 19. 22:58

출처 : unsplash

■ 들어가기

- 파이썬 코딩 도장 (남재윤/길벗). 을 공부하며 정리하는 블로그


▶ Unit36. 클래스 상속 사용하기

     - 36.1 사람 클래스로 학생 클래스 만들기

     - 36.2 상속 관계와 포함 관계 알아보기

     - 36.3 기반 클래스의 속성 사용하기

     - 36.4 메서드 오버라이딩 사용하기

     - 36.5 다중 상속 사용하기

     - 36.6 추상 클래스 사용하기

 

>> 36.5 다중 상속 사용하기 <<

- 다중 상속 : 여러 기반 클래스로부터 상속을 받아서 파생 클래스를 만드는 방법

- 클래스 생성 시 ()(괄호) 안에 클래스 이름을 ,(콤마)로 구분해서 생성

- 사용법
class 기반클래스이름1 :
    코드

class 기반클래스이름2 :
    코드

class 파생클래스이름(기반클래스이름1, 기반클래스이름2) :
    코드
소스 (class_multiple_inheritance.py) 결과
class Person :
    def greeting(self) :
        print('안녕하세요.')

class University :
    def manage_credit(self) :
        print('학점 관리')

class Undergraduate(Person, University) :
    def study(self) :
        print('공부하기')


james = Undergraduate()
james.greeting()        # 기반 클래스 Person의 메서드 호출
james.manage_credit()   # 기반 클래스 University의 메서드 호출
james.study()           # 파생 클래스 Undergraduate에 추가한 study 메서드
안녕하세요.
학점 관리
공부하기

- Person, University, Undergraduate 클래스의 관계

출처 : 파이썬 코딩 도장 (dojang.io)

 

1. 다이아몬드 상속

- 클래스 간의 관계가 다이아몬드 같이 생긴 관계

출처 : 파이썬 코딩 도장 (dojang.io)

- A, B, C 클래스 모두 greeting이라는 같은 메서드를 가지고 있는 경우, D는 어떤 클래스의 메서드를 호출해야할지 애매하다.

- 어떨 때는 A의 메서드를 호출하고, 어떨 때는 B 또는 C의 메서드를 호출하는 것과 같은 경우 문제가 많아 "죽음의 다이아몬드"라 불리기도 함

소스 (class_diamond_inheritance.py) 결과
class A :
    def greeting(self) :
        print('안녕하세요. A입니다.')

class B(A) :
    def greeting(self) :
        print('안녕하세요. B입니다.')

class C(A) :
    def greeting(self) :
        print('안녕하세요. C입니다.')

class D(B, C) :
    pass


x = D()
x.greeting()
안녕하세요. B입니다.

 

2. 메서드 탐색 순서 확인하기

√ 그런데 항상 B의 메서드를 호출하는거 같은데...??

- 메서드 호출 시 인접한 클래스에서부터 찾게 되며, D는 B, C로부터 상속을 받았기 때문에 메서드 조회 시 B클래스부터 찾아서 사용하므로 B의 greeting메서드 "안녕하세요. B입니다."가 반환된다.

- 만약 D가 C, B로부터 상속 받는 것으로 설정된다면 항상 C의 greeting을 우선 반환함

- 위와 같은 다이아몬드 상속에 대한 문제 해결을 위해 파이썬에서는 메서드 탐색 순서(Method Resolution Order, MRO)를 제공

- 사용법 : 클래스.mro()
class A : 
    def greeting(self) : 
        print('안녕하세요. A입니다.') 

class B(A) : 
    def greeting(self) : 
        print('안녕하세요. B입니다.') 

class C(A) : 
    def greeting(self) : 
        print('안녕하세요. C입니다.') 

class D(C, B) : 
    pass 


x = D() 
x.greeting()
안녕하세요. C입니다.

- MRO를 확인하면 메서드 호출 순서는 1) 자기 자신 2) 다중 상속 시 기반클래스 왼쪽부터 오른쪽 순서

>>> D.mro()
[<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]

[참고] object 클래스

- 파이썬에서 object는 모든 클래스의 조상

- 모든 클래스는 object 클래스를 상속 받으므로 기본적으로 object를 생략함

>>> int.mro()
[<class 'int'>, <class 'object'>]
>>> class X :
              pass
>>> class X(object) :   # 위의 생성 방법과 동일
              pass

>> 36.6 추상 클래스 사용하기 <<

- 추상 클래스(abstract class) : 메서드의 목록만 가진 클래스로 상속받는 클래스에서 메서드 구현을 강제하기 위해 사용

- 추상 클래스 만드려면 import로 abc 모듈을 가져와야 함 (abc = abstract base class)

- 클래스의 ()(괄호) 안에 metaclass=ABCMeta를 지정하고,

  메서드를 만들 때 위에 @abstractmethod를 붙혀 추상 메서드 지정

- 사용법
from abc import *

class 추상클래스이름(metaclass=ABCMeta) :
    @abstractmethod
    def 메서드이름(self) :
        코드
소스 (class_abc_error.py) 결과
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 18, in <module>
    james = Student()
TypeError: Can't instantiate abstract class Student with abstract methods go_to_school

- StudentBase를 상속받은 Student에서 추상 클래스 go_to_school을 구현하지 않아 TypeError 발생!

- 추상 클래스를 상속받을 경우 @abstractmethod가 붙은 추상 메서드는 모두 구현해야 함!

소스 (class_abc.py) 결과
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(sefl) :
        print('학교가기')


james = Student()
james.study()
james.go_to_school()
공부하기
학교가기

- 추상 메서드는 호출할 일이 없으므로 빈 메서드로 만듦 (코드에 pass 처리)

 

 

● 요약
1. 추상 클래스 : 인스턴스 생성 시 사용하지 않으며, 오직 상속시에만 사용!
2. 추상 메서드 : 추상 클래스는 인스턴스를 생성할 수 없으므로 추상 메서드도 호출할 일이 없어 빈 메서드(pass)만 생성
3. 다중 상속 시 메서드 호출 순서는 1) 자기 자신 2) 기반 클래스 호출 순서(왼쪽에서 오른쪽) 대로 호출