파이썬

상속

Kiwisae 2022. 11. 9. 10:32
  • 한 클래스가 다른 클래스로부터 데이터 속성(멤버변수)과 메소드를 물려받는 것. (생성자는 상속x)
  • 상속하는 클래스를 기반 클래스 (Base class) 또는 상위 클래스 (Super class) 라고 한다.
  • 상속 받는 클래스는 파생 클래스 (Derived class), 하위 클래스 (Sub class) 라고 한다.

 

 

class Base:
	def base_method(self):
    	print('부모 메소드')
        
#Base 클래스를 상속
class Derived(Base):
	pass			#클래스의 구현을 잠시 미루겠다는 의미. 없으면 내용이 없기 때문에 오류가 난다.
    
base = Base()			#부모 클래스로 객체 생성
base.base_method()		#메소드 호출

derived = Derived()		#자식 클래스로 객체 생성
derived.base_method()		#상속 받은 메소드 호출

 

 

 

 

class Add:			#부모 클래스
	def add(self, n1, n2):
    	return n1 + n2


class Calculator(Add):		#부모 클래스 Add를 상속받은 자식 클래스
	def sub(self, n1, n2):
    	return n1 - n2


ob = Add()			#부모 클래스로 객체 생성
print(ob.add(100, 200))		#부모 클래스에 정의된 메소드
#print(ob.sub(100, 200))	#자식 클래스의 메소드이기 때문에 오류 발생

ojb = Calculator()		#자식 클래스로 객체 생성
print(obj.add(10, 20))		#부모 클래스에게 상속받은 메소드
print(obj.sub(10, 20))		#자식 클래스에 정의된 메소드

 

 

 

 

 

 

다중 상속

자바에서는 하나의 부모에게서만 상속을 받을 수 있지만,

파이썬에서는 여러 부모에게서 상속을 받는 것이 가능하다.

 

파생 클래스의 정의에 기반 클래스의 이름을 콤마(,)로 구분해서 쭉 적어주면 다중 상속이 이루어진다.

 

 

 

 

다이아몬드 상속 

다중 상속이 만들어 내는 곤란한 상황

 

 

 

class Add:
	def add(self, n1, n2):
    print('Add')
    return n1 + n2
    
class Multiply:
	def add(self, n1, n2):
        print('Muliply')
        return n1 + n2
    def multiply(self, n1, n2):
        return n1 * n2
        
#클래스의 다중상속
class Calculator (Add, Multiply)
	def sub(self, n1, n2):
    	return n1 - n2
        
obj = Calculator()		    # 두 부모 클래스에게 상속받은 자식 클래스로 객체 생ㅇ성
print(obj.add(10, 20))              # 30 : Add클래스의 add()실행
print(obj.multiply(10, 20))         # 200
print(obj.sub(10, 20))              # -10

 

 

Add 클래스와 Multiply 클래스 모두 add라는 메소드를 가지고 있다.

실행 시켰을 때 Add라는 메시지가 출력된 것으로 보아 Add의 add를 호출한 것을 알 수 있다.

이는 상속을 받을 때 Add를 먼저 적었기 때문이다.

만약 둘의 순서를 바꾼다면 내용이 달라진다.

 

 

 

 

다중 상속은 이처럼 충돌할 위험성을 내포하고 있다.

 

 

 

 

 

 

메소드 오버라이딩

부모 클래스에게 상속받은 메소드를 자식 클래스에서 재정의하여 사용하는 것을 의미한다.

부모 클래스의 메소드 이름과 형식을 그대로 가져오고, 내용만 다르게 재정의한다.

 

메소드 오버라이딩을 하면, 오버라이딩 된 메소드만 호출된다.

 

부모 클래스의 은닉된 메소드을 호출하기 위해서는

자식 클래스의 메소드 안에서 super() 를 이용하여 호출한다.

 

 

cass A:
	def mymethod(self):		#자식 클래스가 상속하여 오버라이딩하면 은닉된다
    	print('부모 메소드')

class B(A):
	def mymethod(self):		#메소드 오버라이딩
    	super().mymethod()		#부모 클래스의 은닉된 메소드
        print('B클래스의 메소드')
        
class C(A):
	def mymethod(self):		#메소드 오버라이딩
    	print('C클래스의 메소드')
        
a = A()
a.mymethod()

b = B()
b.mymethod()

c = C()
c.mymethod()

 

 

 

 

부모에게서 멤버변수와 메소드를 상속받지만 생성자는 상속의 대상이 아니다.

 

자식 클래스로 객체를 생성할 때에는 자식 클래스의 생성자가 호출된다.

없는 경우, 인터프리터가 기본 생성자를 생성해준다.

 

자식 클래스의 생성자가 호출되면, 부모 클래스의 기본 생성자가 연쇄적으로 호출된다.

 

 

class A:					#부모 클래스
	def __init__(self):			#기본 생성자
    	self.message = 'Hello World'
        
    def print_message(self):			#메소드
    	print(self.message)
        
class B(A):					#자식 클래스
	pass
    
if __name__ == '__main__' :
    #a = A()					#객체 생성 : 생성자 호출
    #a.print_message()
    
    b = B()					#B클래스의 생성자를 호출한다. 
    b.print_message()				#생성자를 만들지 않았지만 자동으로 기본 생성자가 만들어지고, 부모의 기본 생성자를 호출한다.

 

 

 

자식 클래스에 생성자가 있는 경우,

부모 클래스의 기본 생성자를 자동 호출해주지 않는다.

 

자식 클래스에서 부모 클래스의 생성자를 굳이 호출하기 위해서는

super() 를 이용하여 호출해야 한다.

 

class A:				#부모 클래스
	delf __init__(self):		#기본 생성자
    	print('부모 생성자')
        self.message = 'Hello'
        
class B(A):				#자식 클래스
	def __init__(self):		#기본 생성자
    	print('자식 생성자')
        super().__init__()		#부모 클래스의 생성자 호출
        print(self.message)
        
if __name__ == '__main__' :
	b = B()

 

만약 클래스 B의 부모 생성자 호출을 주석 처리 한다면

실행시 오류가 발생한다.

부모 생성자 호출 아래의 코드는 부모의 self.message를 출력하도록 되어 있는데,

부모 생성자는 자식에게 자동으로 상속되지 않는다.

때문에, 일부러 부모 생성자를 호출하지 않기 때문에 self.message도 정의되어 있지 않다.