본문 바로가기

코딩/Python

[Python/파이썬] Class(클래스) 기초 정리 - 3 : 다중상속, super().__init__(), 메서드 오버라이딩

반응형

 

※ 이 글을 쓰는 사람은 SW 비전공자입니다.

※ 개인 공부를 위해 정리하는 글이며, 작성한 코드들은 효율성, 깔끔함(?) 등과는 거리가 멀 수 있습니다.

 

2021.03.14 - [코딩/Python] - [Python/파이썬] Class(클래스) 기초 정리 - 1 : 개념, 사용법

2021.03.20 - [코딩/Python] - [Python/파이썬] Class(클래스) 기초 정리 - 2 : has-a 관계, 상속 개념

2021.03.21 - [코딩/Python] - [Python/파이썬] Class(클래스) 기초 정리 - 3 : 다중상속, super().__init__(), 메서드 오버라이딩

2021.03.22 - [코딩/Python] - [Python/파이썬] Class(클래스) 기초 정리 - 4 : 추상 클래스, 클래스 변수

2021.03.27 - [코딩/Python] - [Python/파이썬] Class(클래스) 메서드 self 설명


 

  1편에서는 Class의 개념이 무엇인지, 파이썬에서 기본 사용법은 어떻게 되는지 정리했다. 2편에서는 객체 속에 객체가 있는 has - a 관계와 클래스 상속 개념에대해서 정리했다. 이번 편에서는 다중 상속, super().__init__() 개념, 메서드 오버라이딩 개념에 대해 공부한 부분을 정리하려고 한다.

 

 

1. 다중상속(Multiple Inheritance)

 

  다중상속은 말그대로 하위클래스가 부모클래스를 여러개 두는 것이다.(여러 클래스에서 상속받음) 이 개념은 객체 지향을 지원하는 언어 모두 사용가능한 것은 아니다. java의 경우에는 지원하지 않는다고 한다. 파이썬에서는 다중상속을 지원한다. 

  아래 코드를 예시로 작성해보았다.

 

#Weapone 클래스 정의
class Weaone:
    def attack(self):
        print("무기는 공격할 수 있어!")    

#Thing 클래스 정의       
class Thing:
    def sell(self):
        print("나는 물건이니 판매할 수도 있지")

#Sword 클래스 정의 : Weapone과 Thing 클래스 상속  
class Sword(Weapone, Thing):
    pass

#Sword 클래스 객체 short_sword 선언
short_sword = Sword()
#Weapone 클래스의 메소드 호출
short_sword.attack()
#Thing 클래스의 메소드 호출
short_sword.sell()

 

<결과>

 

무기는 공격할 수 있어!
나는 물건이니 판매할 수도 있지

 

  Weapone(무기) 클래스와 Thing(물건) 클래스를 정의하였고 Sword(검) 클래스를 정의하여 앞에서 정의한 2가지 클래스를 상속받았다. Sword 클래스로 인스턴스를 생성하면 2개의 부모클래스에 있는 메소드를 호출할 수 있다.

 

 

2. super().__init__()에 대해서

: 부모 클래스의 초기화 메서드 호출하기 (자식 클래스 초기화 메서드에서 호출이 필요할 때)

  

  이 내용은  상속에서 자식 클래스의 초기화 메서드에서 부모 클래스의 초기화 메서드를 호출할 때 필요한 내용이다. 참고로 자식 클래스에서 초기화 메서드를 사용하지 않으면 해당 방법을 사용하지 않아도 된다. 다음과 같은 예시코드를 작성하여 출력해보았다. 

 

#Weapone 클래스 정의
class Weapone:
    def __init__(self):
        self.what = "무기"
        self.type = "근거리"
        print("나는 무기 클래스다!")

#Sword 클래스 정의 : Weapone 클래스 상속  
class Sword(Weapone):
    def __init__(self, power, level):
       self.power = power
       self.level = level

    #Sword 속성(power,level) 및 부모 클래스 Weapon 의 속성 불러오기(what, type)   
    def info(self):
       print("공격력 : ",self.power)
       print("필요레벨 : ",self.level)
       print("무기종류 : ", self.what)
       print("공격타입 : ", self.type)

#Sword 클래스 객체 short_sword 선언
short_sword = Sword(10, 20)
short_sword.info()

 

<결과>

 

    print("무기종류 : ", self.what)
AttributeError: 'Sword' object has no attribute 'what'

 

  에러가 발생한다. 자식 클래스인 Sword에서 정의되지 않은 what과 type이 호출됐기 때문이다. what과 type은 부모클래스에 정의되어 있는데 호출하기 위해선 super().__init__()이라는 생성자를 호출해야 한다. 해당 구문은 자식 클래스 초기화 메서드에서 상속받은 부모클래스의 초기화 메서드를 그대로 불러오기 위해서 사용한다. 

 

  말이 조금 어려운데 쉽게 설명하면 자식 클래스 def __init__() 에서 부모 클래스의 def __init__()을 호출하려면 위 구문을 사용해야한다는 의미이다. 위 코드를 정상적으로 출력하게 하려면 Sword 클래스의 초기화 메서드 부분을 아래와 같이 수정하면 된다. 

 

class Sword(Weapone):
    def __init__(self, power, level):
       super().__init__() #부모 클래스의 초기화 메서드 호출
       self.power = power
       self.level = level

 

<결과>

 

나는 무기 클래스다!
공격력 :  10
필요레벨 :  20
무기종류 :  무기
공격타입 :  근거리

 

 

  super().__init__() 을 응용하여 아래와 같이 코드를 추가 작성해보았다. 효율적인 코드 구조인지는 잘 모르겠다. 여기서는 위 내용을 이해하기 위해서 테스트 코드를 작성해본 것이다. super().__init__(인수1, 인수2) 구조로 사용하여도 정상적으로 결과가 출력된다.

 

#Weapone 클래스 정의
class Weapone:
    def __init__(self, what, type):
        self.what = what
        self.type = type
        print("나는 무기 클래스다!")

#Sword 클래스 정의 : Weapone 클래스 상속  
class Sword(Weapone):
    def __init__(self, power, level, what, type):
       super().__init__(what, type) #부모클래스의 초기화 생성자 호출, what, type 인수)
       self.power = power
       self.level = level

    #Sword 속성(power,level) 및 부모 클래스 Weapon 의 속성 불러오기(what, type)   
    def info(self):
       print("공격력 : ",self.power)
       print("필요레벨 : ",self.level)
       print("무기종류 : ", self.what)
       print("공격타입 : ", self.type)

#Sword 클래스 객체 short_sword 선언
short_sword = Sword(10, 20, "단검", "근거리") #부모클래스 속성 포함 입력
short_sword.info()

 

<결과>

 

나는 무기 클래스다!
공격력 :  10
필요레벨 :  20
무기종류 :  단검
공격타입 :  근거리

 

  위 코드가 복잡해서 아래처럼 도식화해보았다. 즉, 자식 클래스 초기화 메서드 내용에 부모 클래스의 초기화 메서드 내용을 그대로 가져다가 붙힌 것을 super().__init__() 한 줄 코드로 표현한 것이라고 이해하면 될 것 같다.

 

super().__init_()의 이해를 위한 도식화

 

 

3. 메서드 오버라이딩

  

  메서드 오버라이딩은 클래스 상속 관계에서 자식 클래스가 부모 클래스의 메서드를 덮어써서 다른 함수로 사용하는 것이다. 예를 들면 아래와 같은 코드다.

 

#Weapone 클래스 정의
class Weapone:
   def attack(self):
       print("무기는 공격할 수 있다")

#Sword 클래스 정의 : Weapone 클래스 상속  
class Sword(Weapone):
    def attack(self): #메서드 오버라이딩
        print("칼을 무엇이든지 벨 수 있다") 
        super().attack() #부모 클래스의 attack 메서드 호출

short_sword = Sword()
short_sword.attack() 

  

<결과>

 

칼을 무엇이든지 벨 수 있다
무기는 공격할 수 있다

 

  부모 클래스의 attack 메서드가 있지만 자식 클래스에서 동일한 명칭의 attack 메서드를 재정의 하였다. 출력 결과를 보면 덮어씌어진 것으로 보인다.  super().attack()의 경우 부모 클래스 원본 attack 메서드를 출력해보기 위해 임의로 입력해보았다.

 


 

참고링크1 : 코딩도장 - 다중상속 dojang.io/mod/page/view.php?id=2388

참고링크2 : 코딩도장 - 기반 클래스의 속성 사용하기 dojang.io/mod/page/view.php?id=2386

 

728x90