클래스를 상속한다. 부모 클래스를 자식이 상속한다.
(부모 재산을 자식이 상속받는다) 부모는 자식의 상위개념
코드로 상속은 이렇게 표현한다.
class Parent:
pass
class Child(Parent): # 자식이 부모를 상속받았다.
pass
정말 상속이 되는지 확인해보자
class Parent:
finance = 500000000 # 5억
def greeting(self):
print("안녕하세요")
def my_finance(self):
print(f"재산은 {self.finance}원 입니다")
class Child(Parent):
pass
c = Child()
print(c.finance) # 500000000
c.greeting() # 안녕하세요
c.my_finance() # 재산은 500000000원 입니다
# 상속여부 확인
issubclass(Child, Parent) # True
자식 클래스인 Child 에는 변수 finance, 함수 greeting(), my_finance()를 선언해주지 않았음에도 자식이 그대로 상속받아 사용할 수 있다.
생성자, 비공개 변수, 비공개 메소드, staticmethod, classmethod 상속여부 확인해보기
import datetime
class Human:
name = "김민국" # public var
__born = "한국" # Private var
def __init__(self, name, born):
print("Human.__init__")
self.set_public_name(public_name)
self.__set_born(born)
def display_name(self):
print(f"제 이름은 {self.name}, 태어난 곳은 {self.__born} 입니다")
def set_name(self, name):
self.name = name
print(f"제 이름은 {self.name} 입니다")
def __set_born(self, born):
self.__born = born
print(f"전 {self.__born} 에서 태어났어요")
@staticmethod
def birth_to_age(year):
return datetime.datetime.now().year - year
@classmethod
def korean_age(cls, year):
return cls.birth_to_age(year) + 1
# Human.birth_to_age(year) + 1
class Student(Human):
def __init__(self, name):
print("Student.__init__")
self.set_name(name)
def my_born(self):
print(f"제가 태어난 곳은 {self.__born} 입니다")
s = Student("홍길동")
>>> Student.__init__ # Human.__init__ 은 호출되지 않았다
s.my_born()
>>> AttributeError: 'Student' object has no attribute '_Student__born'
# 자식이 부모의 private 변수에 직접 접근할 수 없다
s.display_name()
>>> 제 이름은 홍길동, 태어난 곳은 한국 입니다
# 부모의 함수를 통해서만 부모의 private 에 접근이 가능하다
print(Student.birth_to_age(1999))
>>> 23 # Student를 생성하지 않고도 함수를 사용한다. @staticmethod 상속됨
print(Student.korean_age(1999))
>>> 24 # birth_to_age() 사용하고 +1 한다. @classmethod 상속됨
import random
class Parent:
finance = 500000000 # 5억원
def greeting(self):
print("안녕하세요")
def my_finance(self):
print(f"재산은 {self.finance}원 입니다")
class Child(Parent):
finance = 0 # 자식의 재산 재정의
def greeting(self): # 자식의 인사법 재정의(오버라이딩)
greeting_msgs = ["안녕", "하이", "ㅎㅇ", "hi", "왔냐", "오랜만"]
random.shuffle(greeting_msgs)
print(greeting_msgs[0])
c = Child()
print(c.finance)
c.greeting() # 하이 // 부모는 안녕하세요
c.my_finance() # 재산은 0원 입니다
class Parent:
finance = 500000000
def greeting(self):
print("안녕하세요")
def my_finance(self):
print(f"재산은 {self.finance}원 입니다")
class Child(Parent):
finance = 0 # 자식의 재산 재정의
def greeting(self): # 자식의 인사법 재정의(오버라이딩)
print("하이!")
def my_parents_finance(self):
print(f"부모의 재산은 {super().finance}원 입니다.\n내 재산은 {self.finance}원 입니다")
c = Child()
c.my_parents_finance()
>>> Output
부모의 재산은 500000000원 입니다.
내 재산은 0원 입니다
주의! 부모가 자식의 메소드를 사용할 순 없다.
p = Parent()
p.my_parents_finance()
>>> AttributeError: 'Parent' object has no attribute 'my_parents_finance'
attribute: 클래스 내 메서드나 변수
"""
리스트를 정말 많이 활용하는데..
원래 정의된 리스트는 손대지 않으면서 내가 원하는 부분만 손대보자(확장!)
"""
a = list()
# IDE 에서 Ctrl(Command) + 클릭 해보면 선언 되어있는 곳으로 이동할 수 있다.
# list가 정의되어있는 파일을 따라가보면..
class list(object): # 클래스로 선언되어 있다
... # 기본 메소드들 정의
def append(self, *args, **kwargs):
""" Append object to the end of the list. """
pass
# 확장 클래스 정의
class MyList(list): # 리스트를 상속하는 MyList를 만든다
def append(self, *args, **kwargs):
# 특별한 경우가 아니라면 부모의 인자들은 모두 보존하자
print("append가 호출됐어요")
my_list = MyList() # my_list = list()
my_list.append(10)
print(my_list) # []
list 클래스를 상속받아 append() 메소드를 오버라이딩 했더니, 원래 정의된 .append()가 정의되지 않았다.
print() 문을 유지하면서도, 부모의 append() 기능을 그대로 사용하려면
class MyList(list): # 리스트를 상속하는 MyList를 만든다
def append(self, *args, **kwargs):
super().append(*args, **kwargs) # 부모의 .append()를 그대로 호출
print("append가 호출됐어요")
my_list = MyList()
my_list.append(10)
print(my_list)
>>> Output
append가 호출됐어요 # 자식이 출력한 구문
[10] # 본래 기능이 보존됐다
부모의 기능도 보존하고, 내 의도도 반영되었다.
그럼 이 append() 기능을 조금 변형시켜보자. append를 반복할 횟수를 지정해보면 어떨까?
class MyList(list): # 리스트를 상속하는 MyList를 만든다
def append(self, *args, **kwargs):
if "loop" in kwargs: # kwargs에 loop=n 형식으로 넘어왔다면
loop = kwargs["loop"] # 할당하고
del kwargs["loop"] # 지워줘야 한다. 본래 부모의 append는 loop를 사용하지 않는다.
for i in range(loop):
super().append(*args, **kwargs)
else:
super().append(*args, **kwargs)
my_list = MyList()
my_list.append(1) # 1을 한번 넣고
my_list.append(5, loop=5) # 5를 5번 넣을래
print(my_list) # [1, 5, 5, 5, 5, 5] # 1 한번, 5는 다섯번
클래스는 연쇄 상속이 가능하고, 한번에 여러 클래스를 상속할 수 있다.
class Human:
pass
class Parent(Human):
pass
class Child(Parent):
pass
print(Child.mro()) # 해당 클래스가 어떤 순서로 호출되는지 확인할 수 있다.
>>> [
<class '__main__.Child'>,
<class '__main__.Parent'>,
<class '__main__.Human'>,
<class 'object'>
]
한번에 여러 클래스를 상속할 수 있다
class Human:
pass
class JamMin:
pass
# Parent와 JamMin 두개 클래스를 상속한다.
# 순서는 왼쪽(우선) -> 오른쪽
class Child(Human, JamMin):
pass
print(issubclass(Child, JamMin)) # True
print(issubclass(Child, Human)) # True
print(Child.mro()) # 해당 클래스가 어떤 순서로 호출되는지 확인할 수 있다.
>>> [
<class '__main__.Child'>,
<class '__main__.Human'>,
<class '__main__.JamMin'>,
<class 'object'>
]