ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TIL.33 클래스 상속(기반 클래스 및 파생클래스)
    TIL 2020. 11. 10. 20:51
    728x90

    ## 클래스 상속하기

    ## 클래스 상속(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
Designed by Tistory.