본문 바로가기
Base/Python

27. 상속(Inheritance)과 컴포지션(Composition)

by 귀멸 2023. 6. 30.

혼공파 83~85강

 

1. 상속 기본 

# 초보자 단계에서는 프레임워크에서 만들어진 부모 클래스가 강제하는 상속을 사용한 자식 클래스만 이용!!

class Circle:
    def __init__(self, 반지름):
        self.파이 = 3.14
        self.반지름 = 반지름
    def 넓이(self):
        return self.반지름 * self.반지름 * self.파이
    def 출력(self):
        print("=" * 10)
        print("*" * 10)
        print("=" * 10)
        print(f"원의 반지름: {self.반지름}")
        print(f"넓이 : {self.넓이()}")
        print("=" * 10)
        print("*" * 10)
        print("=" * 10)

class Squre:
    def __init__(self, 길이):
        self.길이 = 길이
    def 넓이(self):
        return self.길이 ** 2
    def 출력(self):
        print("=" * 10)
        print("*" * 10)
        print("=" * 10)
        print(f"정사각형의 한 변의 길이: {self.길이}")
        print(f"넓이 : {self.넓이()}")
        print("=" * 10)
        print("*" * 10)
        print("=" * 10)


circle = Circle(10)
circle.출력()

squre = Squre(10)
squre.출력()

# 훨씬 더 많은 도형에 대한 코드가 반복 된다면...?
# 비슷한 코드가 반복 되고 유지보수도 쉽지 않아진다.

# 이렇게 여러 클래스에 공통된 기능을 하나로 만들어서 상속(Inheritance) 하게 만든다.

위의 코드의 공통된 부분을 묶어서 상속을 활용하여 다시 만들어 보면!!

class Shape:   # 부모클래스 / Super Class
    def __init__():
        raise "생성자를 구현해주세요"
    def 넓이(self):
        raise "넓이 함수를 구현해주세요. 넓이를 리턴하는 함수를 작성해주세요"
    def 출력보조(self):
        raise "출력 보조 함수를 구현해주세요. 출력 전 한마디를 입력해주세요"
    def 출력(self):
        print("=" * 10)
        print("*" * 10)
        print("=" * 10)
        self.출력보조()
        print(f"넓이 : {self.넓이()}")
        print("=" * 10)
        print("*" * 10)
        print("=" * 10)


class Circle(Shape):     # 자식클래스 / Sub Class
    def __init__(self, 반지름):
        self.파이 = 3.14
        self.반지름 = 반지름
    def 출력보조(self):
        print(f"원의 반지름은 {self.반지름}")
    def 넓이(self):
        return self.반지름 * self.반지름 * self.파이
    
class Squre(Shape):
    def __init__(self, 길이):
        self.길이 = 길이
    def 출력보조(self):
        print(f"정사각형 한 변의 길이는 {self.길이}")
    def 넓이(self):
        return self.길이 * self.길이
    
circle = Circle(10)
circle.출력()

squre = Squre(10)
squre.출력()

2. 오버라이드(override) + super()

# 오버라이드
class 부모:
    def 함수(self):
        print("부모의 함수입니다.")

class 자식(부모):
    def 함수(self):
        print("자식의 함수입니다.")
        # 자식 함수에서 부모의 함수를 사용해야하는 경우
        super().함수()

child = 자식()
child.함수()
# 자신의 클래스에 그 함수가 있는가?
# -> 없다면 부모 클래스에 그 함수가 있는가?

활용 예시

# 오버라이드 / super()
class 버튼:
    def __init__(self):
        print("버튼을 초기화합니다.")
        print("버튼을 만듭니다.")
        print("버튼을 화면에 출력합니다.")

class 빨간버튼(버튼):
    def __init__(self):
        super().__init__()
        print("버튼을 빨간색으로 칠합니다.")

class 파란버튼(버튼):
    def __init__(self):
        super().__init__()        
        print("버튼을 파란색으로 칠합니다.")

class 초록버튼(버튼):
    def __init__(self):
        super().__init__()
        print("버튼을 초록색으로 칠합니다.")

빨간버튼()
파란버튼()
초록버튼()

3. 상속과 컴포지션

# 상속과 컴포지션
class Student:
    def __init__(self, 수학):
        self.수학 = 수학
class StudentList(list):    # 기본 자료형을 상속하면서 상속 관련된 내용을 공부
    # 상속 활용의 예 부모의 모든 것 가져오기
    def append(self, 요소):
        if type(요소) != Student:
            raise "Student를 전달해주세요."
        super().append(요소)
    def sum(self):
        output = 0
        for 학생 in self:
            output += 학생.수학
        return output
    def average(self):
        return self.sum() / len(self)
    
학생목록 = StudentList()
학생목록.append(Student(100))
학생목록.append(Student(80))
학생목록.append(Student(70))
# 학생목록.append(100)  # 예외를 발생시킨다
for 학생 in 학생목록:
    print(학생.수학)
학생목록[0] = 0         # AttributeError: 'int' object has no attribute '수학'
print(학생목록.sum())
print(학생목록.average())

# 기본 자료형과 같은 많은 요소를 갖고 있는 클래스를 상속받는 것은 많은 위험 요소가 발생하게 된다.
# 따라서 많은 요소를 갖고 있는 클래스를 상속 받아서 위험 요소를 숨기는 것[블랙 리스트] 보다는
# 많은 요소를 갖고 있는 클래스를 캡슐화로 숨기고 필요한 요소만 공개하는 것[화이트 리스트]가 더 쉽다.

상속을 받지 않고 내부에 캡슐화해서 구현하는 방식을 컴포지션

# 상속과 컴포지션
class Student:
    def __init__(self, 수학):
        self.수학 = 수학
class StudentList:
    def __init__(self):
        self.__리스트 = []    
    def append(self, 요소):
        if type(요소) != Student:
            raise "Student를 전달해주세요."
        self.__리스트.append(요소)
    def sum(self):
        output = 0
        for 학생 in self.__리스트:
            output += 학생.수학
        return output
    def average(self):
        return self.sum() / len(self.__리스트)
    
학생목록 = StudentList()
학생목록.append(Student(100))
학생목록.append(Student(80))
학생목록.append(Student(70))

for 학생 in 학생목록:
    print(학생.수학)
학생목록[0] = 0        
print(학생목록.sum())
print(학생목록.average())


# 상속 : 프레임워크가 상속을 강제한다면 -> 상속
# 컴포지션 : 프레임워크가 강제하는 것이 없다면 컴포지션

댓글