상속(inheritance):
부모 클래스로부터 데이터(field)와 기능(method)를 물려받아서
자식 클래스에서 사용할 수 있도록 하는 개념
- parent (부모), super(상위), base(기본) class
- child (자식), sub(하위), derived(유도) class
class Shape:
def __init__(self, x=0, y=0):
print('Shape.__init__ 호출')
self.x = x
self.y = y
def __repr__(self):
return f'Shape(x = {self.x}, y = {self.y})'
def move(self, dx, dy):
self.x += dx
self.y += dy
if __name__ == '__main__':
shape1 = Shape()
print(shape1)
shape1.move(1, 2)
print(shape1)
출력 결과
Shape.__init__ 호출
Shape(x = 0, y = 0)
Traceback (most recent call last):
Shape(x = 1, y = 2)
class Rectangle(Shape):
def __init__(self, w, h):
print('Rectangle.__init__ 호출')
if __name__ == '__main__':
rect1 = Rectangle(3, 4)
print('rect1 타입: ', type(rect1))
print('rect1: ', rect1) -> 오류
rect1.move(-1, -2)
print(rect1)
실행 결과
File "C:/dev/lab-python/lec06_class/inheritance01.py", line 17, in __repr__
Rectangle.__init__ 호출
return f'Shape(x = {self.x}, y = {self.y})'
rect1 타입: <class '__main__.Rectangle'>
AttributeError: 'Rectangle' object has no attribute 'x'
rect1:
자식 클래스에 __repr__ 메소드가 없기 때문에 부모 클래스의 것을 불러왔을 때,
argument x와 y값이 없어서 오류가 발생
# Child 클래스에서 __init__ 함수를 작성하지 않은 경우에는
# 파이썬 인터프리터가 Parent 클래스의 __init__ 메소드를
# 호출해서 부모 객체를 자동으로 생성함.
# 개발자가 child 클래스에서 __init__ 메소드를 정의한 경우에는
# 파이썬 인터프리터가 parent 클래스의 __init__ 메소드를
# 자동으로 호출하지 않는다.
# Child 클래스에서 parent 클래스의 __init__ 메소드를 명시적으로
# 호출해야 함!
>> __init__ 함수 수정
def __init__(self, w=0, h=0, x=0, y=0):
print('Rectangle.__init__ 호출')
super().__init__(x, y) # 부모 클래스의 __init_ 호출
self.w = w
self.h = h
if __name__ == '__main__':
rect1 = Rectangle(w=3, h=4, x=0, y=0)
print('rect1 타입:', type(rect1))
print('rect1:', rect1)
rect1.move(-1, -2)
print(rect1)
실행 결과
Rectangle.__init__ 호출
Shape.__init__ 호출 # 부모 클래스의 __init_ 호출
rect1 타입: <class '__main__.Rectangle'>
rect1: Shape(x = 0, y = 0) # 부모의 메소드 __repr__ 실행 + x, y 값만 적용
Shape(x = -1, y = -2) # 부모의 메소드 move 실행
Rectangular 클래스에서 __repr__함수 생성 >> 오버라이드 override
# override : 부모 클래스로부터 상속받은 메소드를
# 자식 클래스에서 재정의하는 것.
def __repr__(self):
return f'사각형(가로={self.w}, 세로={self.h}, x={self.x}, y={self.y})'
print('rect1:', rect1) # override한 __repr__ 메소드가 호출 됨
rect1.move(-1, -2) # 부모에게서 상속받은 move 메소드가 호출 됨
print(rect1)
실행 결과
rect1: 사각형(가로=3, 세로=4, x=0, y=0)
사각형(가로=3, 세로=4, x=-1, y=-2)
# overloading:
# 함수(메소드)의 파라미터가 다른 경우
# 같은 이름으로 여러개의 함수(메소드)를 정의하는 것
# 파이썬은 overloading을 제공하지 않음
class Circle(Shape):
def __init__(self, r=0, x=0, y=0):
print('Circle.__init__ 호출')
# super 클래스의 __init__ 메소드를 반드시 호출해야 함!
# super().__init__(x, y)
Shape.__init__(self, x, y) # self를 생략 불가 !
# sub 클래스만 갖는 field를 초기화
self.r = r
def __repr__(self):
return f'동그라미(반지름 = {self.r}, x = {self.x}, y = {self.y})'
circle1 = Circle(r=10, x=0, y=0)
print('circle1 type: ', type(circle1))
print(circle1)
출력 결과
Circle.__init__ 호출
Shape.__init__ 호출
circle1 type: <class '__main__.Circle'>
동그라미(반지름 = 10, x = 0, y = 0)
"""
class Shape:
"""
def area(self):
"""
# Shape 객체는 넓이를 계산할 수 없고,
# Shape 의 sub 타입들인 Rectangle, Circle 객체가
# 각자의 방식으로 계산해야 됨
:return: 도형의 넓이
"""
raise NotImplementedError("area 메소드는 반드시 Override")
def draw(self):
"""
넓이를 계산하는 area 메소드를 사용해서 도형 내부를
그려주는 메소드
:return: None
"""
print(f'Drawing area {self.area()}...')
rect1.draw()
circle1.draw()
출력 결과
Drawing area None
Drawing area None
"""
class : Rectangle
"""
def area(self):
return self.w * self.h
# Class : Circle
# from math import pi
def area(self):
return pi * self.r ** 2
rect1.draw()
circle1.draw()
출력 결과
Drawing area 12
Drawing area 314.1592653589793
'Python > Python기초' 카테고리의 다른 글
Python 29_ 파일 디렉토리 다루기2 ->파일 읽기 (0) | 2019.12.30 |
---|---|
Python 28_ 파일 디렉토리 다루기, [os 모듈] 의 변수와 함수들 (0) | 2019.12.27 |
Python 26_class 설계 + __**__ 더블 언더스코어 메소드 (0) | 2019.12.25 |
Python 25_ 객체지향프로그래밍, class (0) | 2019.12.24 |
Python 24_직접 Module 만들기, __init__.py, from ~ import ~ 구문 (0) | 2019.12.23 |