[python] 클래스 상속 사용하기

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

# 클래스 상속은 다음과 같이 클래스를 만들 때 ()를 붙이고 안에 부모 클래스 이름을 붙인다.
# class 부모클래스이름:
#     코드
#
# class 자식클래스이름(부모클래스이름):
#     코드
# 사람 클래스를 만들고 이를 상속받는 학생 클래스를 만들어보자.
class Person:
    def greeting(self):
        print('안녕하세요')


class Student(Person):
    def study(self):
        print('공부하기')


james = Student()
james.greeting()  # 안녕하세요. 부모 클래스 Person의 greeting 호출
james.study()  # 공부하기. 자식 클래스 Student의 study 호출

# 이러한 상속 관계를 확인하고 싶을 때는 issubclass 함수를 사용하면 된다.
# 이 함수는 어떤 클래스가 부모 클래스의 자식 클래스인지 확인한다.
print(issubclass(Student, Person))  # Student는 Person의 자식 클래스이므로 True

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

# IS-A 관계: 동등한 관계를 말한다.
# 예로, 학생은 사람이다. 처럼 말했을때 말이 된다면 IS-A 관계이다.
class Person:
    def greeting(self):
        print('안녕하세요.')


class Student(Person):
    def study(self):
        print('공부하기')


# 동등 관계가 아니라 사람 목록을 관리하는 등의 포함 관계를 갖는 클래스를 만든다면
# 리스트 속성에 Person 인스턴스를 넣어서 관리하면 된다.
class PersonList:
    def __init__(self):
        self.person_list = []  # 리스트에 Person 인스턴스를 넣어서 관리

    def append_person(self, person):  # 리스트 속성에 Person 인스턴스를 추가하는 메소드
        self.person_list.append(person)

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

# 자식 클래스의 __init__에서는 super()를 사용해서 __init__ 메소드를 호출해줘야 한다.
# 그렇지 않으면 부모 클래스에 있는 속성이 만들어지지 않아 접근이 불가능하기 때문이다.
class Person:
    def __init__(self):
        print('Person __init__')
        self.a = 'aaa'


class Student(Person):
    def __init__(self):
        print('Student __init__')
        super().__init__()  # 부모 클래스의 __init__ 메소드 호출
        self.b = 'bbb'


james = Student()  # Student __init__  Person __init__
print(james.b)  # bbb
print(james.a)  # aaa

# 만약 자식 클래스에서 __init__ 메소드를 생략한다면 부모 클래스의 __init__ 이 자동으로 호출되므로
# super()는 사용할 필요가 없다.

메소드 오버라이딩 사용하기

# 이번에는 자식 클래스에서 부모 클래스의 메소드를 새로 정의하는 메소드 오버라이딩에 대해 알아보자.
# 아래와 같이 부모 클래스와 자식 클래스에 같은 메소드를 만들어보면,
class AAA:
    def foo(self):
        print('AAA')


class BBB:
    def foo(self):
        # super().foo()  # 이렇게 상위 클래스의 메소드를 호출하는 것도 가능하다.
        print('BBB')


obj = BBB()
obj.foo()  # BBB가 출력된다. 부모 클래스의 foo를 무시하고 자식 클래스의 foo를 호출한다.
# 이렇게 상위 클래스의 메소드를 무시하는 하위 클래스의 메소드를 만드는 것을 메소드 오버라이딩 이라고 한다.

다중 상속 사용하기

# 다중 상속은 여러 부모 클래스로부터 상속을 받아 자식 클래스를 만드는 방법이다.
# 클래스를 만들 때 괄호 안에 클래스 이름을 , 로 구분해서 넣어주면 된다.
class AAA:
    def aaa(self):
        print('AAA')


class BBB:
    def bbb(self):
        print('BBB')


class CCC(AAA, BBB):
    def ccc(self):
        print('CCC')


# 이렇게 해서 만든 CCC 클래스는 AAA와 BBB 클래스를 모두 상속받았다.
# 그렇기 때문에 AAA, BBB 클래스의 aaa, bbb 메소드를 모두 사용 가능하다.
obj = CCC()
obj.aaa()  # AAA
obj.bbb()  # BBB
obj.ccc()  # CCC

# 그런데 이 때, AAA 클래스와 BBB 클래스가 둘 다 foo() 메소드를 갖고 있다면
# CCC는 어떤 클래스의 foo()를 호출해야 할까?
# 클래스이름.mro() 를 통해서 메소드 탐색 순서를 확인할 수 있다.
print(CCC.mro())  # [<class '__main__.CCC'>, <class '__main__.AAA'>, <class '__main__.BBB'>, <class 'object'>]
# 즉, 상속 클래스 목록에서 왼쪽에 있는 것부터 탐색을 한다.

추상 클래스 사용하기

from abc import *


# 파이썬은 추상 클래스라는 기능을 제공한다.
# 추상 클래스는 메소드의 목록만 가진 클래스이며 상속받는 클래스에서 메소드 구현을 강제하기 위해 사용한다.
# 만약 한 클래스라도 구현이 되어있지 않다면 에러가 발생한다.
# 추상 클래스를 만들려면 abc(abstract base class) 모듈을 import 해야한다.
# 그리고 클래스의 () 안에 metaclass=ABCMeta를 지정하고,
# 메소드를 만들 때 위에 @abstractmethod 를 붙여서 추상 메소드로 지정한다.
# 학생 추상 클래스 StudentBase를 만들고 이 추상 클래스를 상속받아 Student 클래스를 만들어보자.
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('학교가기')


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

# 이처럼 추상 클래스는 상속받는 클래스가 반드시 구현해야 하는 메소드를 정해줄 수 있다.
# 추상 클래스는 인스턴스를 만들기 위한 목적이 아니므로 추상 클래스로 인스턴스를 만들려고 하면 에러가 발생한다.
# 즉, 오로지 상속에만 추상 클래스를 사용한다.

Updated:

Leave a comment