-
TIL.33 클래스 상속(기반 클래스 및 파생클래스)TIL 2020. 11. 10. 20:51728x90반응형
## 클래스 상속하기
## 클래스 상속(inheritance)
## 상속이란 무언가를 물려준다는 뜻으로 클래스 상속은 기반 클래스(base class)에서 상속을 받아
새롭게 만드는 클래스를 파생 클래스(derived class)라 한다.
## 클래스 상속은 물려받은 기능을 유지한채로 다른 기능을 추가할 때 사용하는 기능이다.
## 보통 기반 클래스는 부모 클래스(parent class), 슈퍼 클래스(superclass)라고 부르고
## 파생 클래스는 자식 클래스(child class), 서브 클래스(subclass)라고도 부른다.
## 클래스 상속은 기반 클래스의 기능을 그대로 활용하면서 다른 기능을 추가할때 사용하는데,
# 그렇다면 왜 굳이 클래스를 새로 만들지 않고 클래스 상슥을 시켜 파생 클래스를 만드는걸까?
## 만약에 새로운 기능이 필요할때마다 클래스를 새로 만들면 중복되는 부분을 반복해서 만드는 경우가 생긴다.
# 예를들어
# 아래 그림에서 조류와 어류를 표현하고자 할때
# 생물이고, 동물이고, 척추동물이고 조류이다. 로 표현할때
# 생물이고, 동물이고, 척추동물이고 어류다. 처럼 불필요하게 반복을 만들어야하는데,
## 이럴때 상속을 이용하면 중복된 부분을 새로 만들지 않아 더 효율적이라 이해하자.
class Person: def greeting(self): print('안녕') class Student (Person): def study (self): print('공부하기') james = Student() james.greeting() # 안녕 / # Student 클래스에는 greeting메서드가 없지만 Person의 파생클래스로서 # Person의 기능을 물려받는 상속을 해준 상태이므로 # Person에 있는 greeting메서드를 찾아가 정상 동작한다. james.study() # 공부하기 # Student 클래스에는 greeting 메서드가 없지만 # Person 클래스를 상속받았으므로 greeting 메서드를 호출할 수 있다.
## 사람 클래스와로 학생 클래스 만들기
## 이처럼 클래스 상속은 기반 클래스의 기능을 유지하면서 새로운 기능을 추가 할 수 있다.
## 특히 클래스 상속은 연관되면서 동등한 기능일 때 사용한다.
## 학생은 사람이므로 연관된 개념이고, 학생은 사람에서 역할만 확장되었을뿐 동등한 개념이다.
## 클래스 상속 관계 확인하기.
# 클래스의 상속 관계를 확인하고 싶을 때는 issubclass 함수를 사용한다.
# 클래스가 기반 클래스의 파생 클래스인지 확인하여,
기반 클래스의 파생 클래스가 맞으면 True, 아니면 False를 반환합니다.
# issubclass(파생클래스, 기반클래스)
class Person: pass class Student(Person): pass print(issubclass(Student, Person)) :: True
## 상속 관계와 포함 관계
## 상속 관계
class Person: def greeting(self): print('안녕하세요.') class Student(Person): def study(self): print('공부하기')
# 앞에서 만든 Student 클래스는 Person 클래스를 상속받아 만들었다.
## 여기서, "학생은 사람이다"와 같이 학생 Student는 사람 Person이므로 같은 종류이다.
## 이처럼 상속은 명확하게 같은 종류이며 동등한 관계일 때 사용한다.
즉, "학생은 사람이다."라고 했을 때 말이 되면 동등한 관계이다.
## 상속관계는 영어로 "is a" 관계라고 부른다. (Student is a Persion)
## 포함 관계
## 그렇다면 학생 클래스가 아닌 사람 목록을 관리하는 클래스를 만든다면 어떻게 해야 할까?
# 다음과 같이 리스트 속성에 Person 인스턴스를 넣어서 관리하면 된다.
class Person: def greeting(self): print('안녕하세요.') class PersonList: def __init__(self): self.person_list = [] # 리스트 속성에 Person 인스턴스를 넣어서 관리 def append_person(self, person): # 리스트 속성에 Person 인스턴스를 추가하는 함수 self.person_list.append(person)
## 여기서는 상속을 사용하지 않고 속성에 인스턴스를 넣어서 관리하므로 PersonList가 Person을 포함하고 있다.
## 이러면 사람 목록 PersonList와 사람 Person은 동등한 관계가 아니라 포함 관계이다.
## 즉, "사람 목록은 사람을 가지고 있다."라고 말할 수 있으며, 포함 관계를 영어로 "has-a" 관계라고 부른다 (PersonList has a Person).
### 정리하자면 같은 종류에 동등한 관계일 때는 상속을 사용하고,
그 이외에는 속성에 인스턴스를 넣는 포함 방식을 사용하면 된다.
## 기반 클래스의 속성 사용하기
# 다음과 같이 Person 클래스에 hello 속성이 있고, Person 클래스를 상속받아 Student 클래스를 만든다.
# 그다음에 Student로 인스턴스를 만들고 hello 속성에 접근해보자.
class Person: def __init__(self): print('Person __init__') self.hello = '안녕하세요.' class Student(Person): def __init__(self): print('Student __init__') self.school = '파이썬 코딩 도장' james = Student() print(james.school) print(james.hello) # 기반 클래스의 속성을 출력하려고 하면 error가 발생함
## 기반 클래스의 기능을 물려받는다고 하였는데, 왜 기반 클래스의 hello 속성에 접근하지 못하는 걸까
## 이유는 기반 클래스의 __init__메서드가 호출되지 않았기 때문이다
당연히 hello라는 속성이 만들어지지 못했기 때문이다.
## 즉, 기반 클래스 Person의 __init__ 메서드가 호출되지 않으면
self.hello = '안녕하세요.'도 실행되지 않아 속성이 만들어지지 않아 호출할 수 없다.
## super()로 기반 클래스 초기화하기
## 위와 같이 기반 클래스의 __init__가 호출되지 않는 문제는
super()를 사용해서 기반 클래스의 __init__ 메서드를 호출해주면 된다.
### 즉, super()를 사용하면 기반 클래스의 메서드를 사용하겠다는 의미로 이해하자.
# 다음과 같이 super() 뒤에 .(점)을 붙여서 메서드를 호출하는 방식이다.
# super().메서드()
class Person: def __init__(self): print('Person __init__') self.hello = '안녕하세요.' class Student(Person): def __init__(self): print('Student __init__') super().__init__() # super()로 기반 클래스의 __init__ 메서드 호출/ 위코드와 다른점 self.school = '파이썬 코딩 도장' james = Student() print(james.school) print(james.hello)
기반 클래스 Person 의 속성 hello 를 찾는 과정 # 실행을 해보면 기반 클래스 Person의 속성인 hello가 잘 출력된다.
## super().__init__()와 같이 기반 클래스 Person의 __init__ 메서드를 호출해주면 기반 클래스가 초기화되어서 속성이 만들어진다고 한다.
# (기반 클래스를 초기화된다는 말이 이해가 가질 않는다 - 질문)
# 실행 결과를 보면 'Student __init__'과 'Person __init__'이 모두 출력된다.
## 여기서 print를 각 사용하였을때의 결과이다.
james = Student() print(james.school) # Student __init__ Person __init__ 파이썬 코딩 도장 print(james.hello) # Student __init__ Person __init__ 안녕하세요. print(james.school) print(james.hello) # Student __init__ Person __init__ 파이썬 코딩 도장 안녕하세요.
## print를 2번 연속사용하면 Student와 Person의 메서드가 "한번씩만" 호출되어 결과가 나오는것으로 생각한다.
## 기반 클래스를 초기화하지 않아도 되는 경우 (super() 사용하지 않는방법)
class Person: def __init__(self): print('Person __init__') self.hello = '안녕하세요.' class Student(Person): pass james = Student() print(james.hello) # Person __init__ 안녕하세요.
## 이처럼 파생 클래스의 __init__메서드가 없다면
## 기반 클래스의 __init__이 자동으로 호출되므로 기반 클래스의 속성을 사용할 수 있다.
## 좀더 명확하게 super 사용하기
## super는 다음과 같이 파생 클래스와 self를 넣어서 현재 클래스가 어떤 클래스인지 명확하게 표시하는 방법도 있다.
# 물론 super()와 기능은 같다.
# super(파생클래스, self).메서드
class Student(Person): def __init__(self): print('Student __init__') super(Student, self).__init__() # super(파생클래스, self)로 기반 클래스의 메서드 호출 self.school = '파이썬 코딩 도장'
728x90반응형'TIL' 카테고리의 다른 글
TIL.35 두점 사이의 거리 구하기 (0) 2020.11.12 TIL.34 클래스 상속(오버라이딩 및 추상클래스) (0) 2020.11.11 TIL.32 클래스의 속성과 메서드 (0) 2020.11.09 TIL. 31 클래스의 속성, 비공개 속성 사용하기 (0) 2020.11.08 TIL.30 클래스와 메서드 사용하기 (0) 2020.11.07