상속이란, 윗사람이 돌아가시면 그 슬하에 배우자 혹은 자녀에게 재산이 승계된다는 것을 의미한다.
즉, 윗사람의 재산이라는 속성값이 자식들이라는 개체에 스며든다고 볼 수 있다. 따라서 일단 좋다고 볼 수 있다.
갑자기 뜬금없는 소리냐고? 아니다. 우리의 삶과 마찬가지로 코드 또한 삶이? 녹아있다...
절차 지향이 아닌 객체 지향 프로그래밍 (ObjectOrientedProgramming) 을 지원하는 프로그래밍 언어는
클래스에서 상속 기능을 지원한다. 즉, 자식이 부모님으로부터 재산 등을 상속 받는 것처럼 다른 클래스에 이미 구현된 메서드나 속성을 상속한 클래스에서는 그러한 메서드나 속성을 그대로 사용할 수 있게 된다.
클래스의 상속을 또 다른 관점에서 생각해보면 클래스를 상속한다는 뜻은 부모 클래스의 능력을 그대로 전달 받는 것을 의미한다. 인간으로 치면 부모로부터 유전적 특성을 물려받아 부모의 능력을 자식이 물려받는 것과 비슷하다.
노래를 잘 부르는 가수의 부모 클래스가 있다고 생각해보자. 이를 파이썬으로 표현하면 다음과 같이 노래를 부르는 메서드가 포함된 클래스를 정의 할 수 있다.
class Parent :
def can_sing(self):
print("Sing a song")
Parent 클래스에서 정의 했으니 클래스의 인스턴스를 생성해본다. 그리고 노래를 정말 할 수 있는지도 메서드를 호출해 확인해본다.
>>> father = Parent()
>>> father.can_sing()
Sing a song
이번에는 노래를 잘 부르는 Parent 클래스로 부터 상속을 받은 노래 좀 하는 자식 클래스를 정의해본다.
클래스의 이름은 HynnChild 라고 하겠다. ( 개인적으로 박혜원님 노래를 좋아한다. ) 클래스를 정의할 떄 다른 클래스로부터 상속 받고자 한다면 새로 정의할 클래스 이름 다음에 괄호를 사용해 상속받고자 하는 클래스의 이름을 지정하면 된다. HynnChild 클래스는 상속받기 전까지는 아무런 능력이 없어 내부 메서드를 구현하지 않고 pass 로 완성한다.
>>> class HynnChild(Parent):
pass
Parent 클래스로부터 상속받은 HynnChild 클래스에 대한 인스턴스를 생성하고 노래를 시켜본다.
중요한 포인트는 현재 HynnChild 에는 어떤 메서드도 존재하지 않는다는 점이다. 다음 코드를 보면 부모 클래스로부터
상속 받아서 그런지 자신은 메서드를 포함하지않아도 바로 노래를 잘 불러버린다.
>>> child1 = HynnChild()
>>> child1.can_sing()
Sing a song
이번에는 부모로부터 어떤 능력 혹은 재산도 상속받지 못한 자식 클래스(UninheriedChild) 를 만들어 본다.
>>> class UninheritedChild:
pass
당연히 인스턴스 생성후 뭘해도 아무것도 하지못한다. 그럼 혼자 노력해서 되도록 연습? 하면 된다. 프로그래밍 측면에서는 직접 메서드를 구현해야 한단 뜻이다. 아래를 보자.
>>> child2 = UninheritedChild()
>>> child2.can_sing()
Traceback (most recent call last):
File "<pyshell#53>", line 1, in <module>
child2.can_sing()
AttributeError: 'UninheritedChild' object has no attribute 'can_sing'
당연, 상속 안받고 자수성가할 수 있다. 부모 클래스에서 구현된 메서드를 그대로 복사해서 새로 정의할 클래스에 코드를 붙여넣기 식으로 사용할 수도 있다 하지만, 그렇게 하면 같은 기능을 하는 코드가 중복되기 때문에 코드를 관리하기 어렵고 복사 및 붙여넣기를 해야 하므로 불편하다. (C++의 경우 동일한 클래스가 다른 곳에서 #include 호출되면 에러가 발생한다 #include ~(클래스이름)~.h 가 클래스를 그대로 맨위에 붙여넣는 것으로 인식하기 때문...)
아무튼 별로다. 이에 반해 클래스의 상속이라는 기능을 이용하면 최소한의 코드로 부모 클래스에서 구현된 메서드를 손쉽게 바로 이용해먹을 수 있다.
+ 추가
class Car :
"""Parent Class"""
def __init__(self, tp, color) :
self.type = tp
self.color = color
def show(self):
return 'Car Class "Show Method!"'
class BmwCar(Car) :
"""Sub Class"""
def __init__(self, car_name, tp, color):
super().__init__(tp,color)
self.car_name = car_name
def show_model(self) -> None:
return "Your Car Name : %s" % self.car_name
class BenzCar(Car) :
"""Sub Class"""
def __init__(self, car_name, tp, color):
super().__init__(tp,color)
self.car_name = car_name
def show_model(self) -> None:
return "Your Car Name : %s" % self.car_name
def show(self):
print(super().show()) # super를 사용하여 부모 요소 생성자 메소드에 접근 가능하다.
return 'Car Info : %s %s %s' %(self.car_name, self.type, self.color) # Sub 클래스에서 작성, 수정 ,추가된 것을 우선한다 overriding 오버라이딩
위 코드와 같이 super 를 사용하여 부모 요소 생성자 메소드에 접근할 수있다. 아래는 호출한 코드다.
( 호출시 클래스 함수에서 선언된 변수의 순서대로 아래 인스턴스 변수에 입력을 줘야 정확히 같은 속성값 위치에 저장된다. )
# 일반 사용
model1 =BmwCar('520d','sedan','red')
print(model1.color) # Super
print(model1.type) # Super
print(model1.car_name) # Sub
print(model1.show()) # Super
print(model1.show_model()) # Sub
print(model1.__dict__)
# Method Overriding(오버라이딩)
model2 = BenzCar("220d",'suv','black')
print(model2.show())
# Parent Method Call
model3 = BenzCar("350d",'sedan','silver')
print(model3.show())
# Inheritance Info (상속 정보를 리스트 형태로 반환 => 'mro()' )
print(BmwCar.mro())
print(BenzCar.mro())
# 예제2
# 다중 상속
class X():
pass
class Y():
pass
class Z():
pass
class A(X, Y):
pass
class B(Y, Z):
pass
class M(B, A, Z):
pass
print(M.mro())
print(A.mro())
# 너무 복잡한 다중 상속은 가독성이 떨어져서 권장하지 않는다 보통 2개~3개 정도? 상속
결과는 아래와 같다.
red
sedan
520d
Car Class "Show Method!"
Your Car Name : 520d
{'type': 'sedan', 'color': 'red', 'car_name': '520d'}
# Method Overriding(오버라이딩)
Car Class "Show Method!"
Car Info : 220d suv black
# Parent Method Call
Car Class "Show Method!"
Car Info : 350d sedan silver
# Inheritance Info (상속 정보를 리스트 형태로 반환 => 'mro()' )
[<class '__main__.BmwCar'>, <class '__main__.Car'>, <class 'object'>]
[<class '__main__.BenzCar'>, <class '__main__.Car'>, <class 'object'>]
[<class '__main__.M'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.X'>, <class '__main__.Y'>, <class '__main__.Z'>, <class 'object'>]
[<class '__main__.A'>, <class '__main__.X'>, <class '__main__.Y'>, <class 'object'>]
Press any key to continue . . .
< 오버라이딩 overriding >
부모 클래스에서 상속을 받은 자식 클래스에서 부모 클래스의 재산을 불리거나 제거하고 다른 재산을 투입할 수 있는 것을 말한다. 다시말해 위에서처럼 def show(self) 같은 함수는 부모와 자식에서 중복되는데 자식클래스에서 재정의해서
(즉, 이를 오버라이딩해서 사용한다고 한다) 바인딩할 수 있다는 것이다. 부모이기는 자식없다는 것이다. 자식이 원하면 부모님의 유전적 특성을 이어받아 노래를 더 잘 부를 수도 있고 환경적 요인에 의해 다른 길로 갈 수 있는 것이다.
파이썬은 다중 상속이 가능하다. 다중 리턴이 되듯이...
암튼 해보면 너무 다중하게 상속되면 복잡하게 된다. 즉, 족보가 꼬인다는 뜻?
가능하면 GrandParentClass까진 두진말자.
< mro() >
상속관계를 보여준다. 뒤에서부터 object 클래스 - > Car 클래스 -> BmwCar 클래스로 상속된다는 뜻이다.
*파이썬은 기본적으로 object 클래스의 유전 특성을 물려받았다. 는 사실도 알게됐다.
이에 관련된 사항은 추후 업로드 할 예정이다.
P.S - object 클래스에 관하여...
'python' 카테고리의 다른 글
python - 외부 파일 처리/ Excel , CSV 파일 읽기 및 쓰기 (0) | 2020.04.29 |
---|---|
python - 에러 및 예외 처리 (0) | 2020.04.28 |
python - 파일 읽기 / 쓰기 (2) | 2020.04.28 |
Python - 파이썬 모듈, 패키지 (0) | 2020.04.26 |
Python - 클래스 변수와 인스턴스 변수 - 공부 생각 노트 (0) | 2020.04.26 |