TIL_28 : 상속

32125 단어 TILOOPOOP

🙄 상속


➡ 상속이란?

  • 두 클래스 사이에 부모-자식 관계를 설정하는 것
  • 자식 클래스는 부모 클래스의 모든 변수와 메소드를 상속 받음

➡ 부모 클래스 정의하기

  • 아래 두 클래스는 유사한 부분이 많은 계산대 직원 클래스, 배달 직원 클래스
  • 부모 클래스 Employee를 만들어보자
class Cashier:
    """계산대 직원 클래스"""
    company_name = "버거버거"
    raise_percentage = 1.03
    burger_price = 4000

    def __init__(self, name, wage, number_sold=0):
        self.name = name
        self.wage = wage
        self.number_sold = number_sold

    def raise_pay(self):
        """시급을 인상한다"""
        self.wage *= self.raise_percentage

    def take_order(self, money_received):
        """주문과 돈을 받고 거스름돈을 리턴한다"""
        if Cashier.burger_price > money_received:
            print("돈이 충분하지 않습니다.")
            return money_received
        else:
            self.number_sold += 1
            change = money_received - Cashier.burger_price
            return change

    def __str__(self):
        return Cashier.company_name + " 계산대 직원: " + self.name
class DeliveryMan:
    """배달원 클래스"""
    company_name = "버거버거"
    raise_percentage = 1.03

    def __init__(self, name, wage, on_standby):
        self.name = name
        self.wage = wage
        self.on_standby = on_standby

    def raise_pay(self):
        """시급을 인상한다"""
        self.wage *= self.raise_percentage

    def deliver(self, address):
        """배달원이 대기 중이면 주어진 주소로 배달을 보내고 아니면 설명 메시지를 출력한다"""
        if self.on_standby:
            print(address + "로 배달 나갑니다!")
            self.on_standby = False
        else:
            print("이미 배달하러 나갔습니다!")

    def back(self):
        """배달원을 복귀 처리한다"""
        self.on_standby = True

    def __str__(self):
        return DeliveryMan.company_name + " 배달원: " + self.name
  • 중복되는 부분을 부모 클래스에 써주고 자식 클래스에서 지우면 됨
class Employee:
    """직원 클래스"""
    company_name = "버거버거"
    raise_percentage = 1.03

    def __init__(self, name, wage):
        self.name = name
        self.wage = wage

    def raise_pay(self):
        """시급을 인상한다"""
        self.wage *= self.raise_percentage

    def __str__(self):
        return Employee.company_name + " 직원: " + self.name


class Cashier:
    burger_price = 4000

    def __init__(self, name, wage, number_sold=0):
        self.number_sold = number_sold

    def take_order(self, money_received):
        """주문과 돈을 받고 거스름돈을 리턴한다"""
        if Cashier.burger_price > money_received:
            print("돈이 충분하지 않습니다.")
            return money_received
        else:
            self.number_sold += 1
            change = money_received - Cashier.burger_price
            return change


class DeliveryMan:
    def __init__(self, name, wage, on_standby):
        self.on_standby = on_standby

    def deliver(self, address):
        """배달원이 대기 중이면 주어진 주소로 배달을 보내고 아니면 설명 메시지를 출력한다"""
        if self.on_standby:
            print(address + "로 배달 나갑니다!")
            self.on_standby = False
        else:
            print("이미 배달하러 나갔습니다!")

    def back(self):
        """배달원을 복귀 처리한다"""
        self.on_standby = True

👉 지금까지는 서로 다른 클래스 3개일뿐 상속관계가 아님
👉 class 자식 클래스(부모 클래스): 로 상속관계 설정


상속관계 설정하기

class Employee:
    """직원 클래스"""
    company_name = "버거버거"
    raise_percentage = 1.03

    def __init__(self, name, wage):
        self.name = name
        self.wage = wage

    def raise_pay(self):
        """시급을 인상한다"""
        self.wage *= self.raise_percentage

    def __str__(self):
        return Employee.company_name + " 직원: " + self.name


class Cashier(Employee):
    pass


goldstlme = Cashier("민정호", 8900)

goldstlme.raise_pay()
print(goldstlme.wage)
print(goldstlme)

# 9167.0
# 버거버거 직원: 민정호

👉 Cashier는 비어있지만 부모 클래스의 인스턴스, 메소드 정상 작동


➡ 상속과 관련된 메소드 & 함수

  • .mro() : 인스턴스의 클래스가 어떤 부모 클래스를 가지는지 보여준다.
  • isinstance() : 특정 클래스의 인스턴스가 맞는지 판별
    1. 첫 번째 파라미터에는 검사할 인스턴스의 이름
    2. 두 번째 파라미터에는 기준 클래스의 이름
  • issubclass() : 한 클래스가 다른 클래스의 자식 클래스인지 판별
    1. 첫 번째 파라미터로 검사할 클래스의 이름
    2. 두 번째 파라미터에는 기준이 되는 부모 클래스의 이름
class Employee:
    """직원 클래스"""
    company_name = "버거버거"
    raise_percentage = 1.03

    def __init__(self, name, wage):
        self.name = name
        self.wage = wage

    def raise_pay(self):
        """시급을 인상한다"""
        self.wage *= self.raise_percentage

    def __str__(self):
        return Employee.company_name + " 직원: " + self.name


class Cashier(Employee):
    pass


class DeliveryMan(Employee):
    pass
    
    
goldstlme = Cashier("민정호", 8900)

print(Cashier.mro())
# [<class '__main__.Cashier'>, <class '__main__.Employee'>, <class 'object'>]

print(isinstance(goldstlme, Cashier))		# True
print(isinstance(goldstlme, DeliveryMan))	# False
print(isinstance(goldstlme, Employee))		# True
# 자식 클래스로 만든 인스턴스는 부모 클래스의 인스턴스이기도 하다!!

print(issubclass(Cashier, Employee))		# True

➡ 오버라이딩

  • 오버라이딩 : 덮어쓰기, 부모로부터 물려받은 것을 자신에 맞게 수정
  • 물려받기만 해서는 자식 클래스를 제대로 사용할 수 없다
  • 물려받기만 하면 자식클래스들간의 차이가 없기 때문
class Employee:
    """직원 클래스"""
    company_name = "버거버거"
    raise_percentage = 1.03

    def __init__(self, name, wage):
        """인스턴스 변수 설정"""
        self.name = name
        self.wage = wage

    def raise_pay(self):
        """시급을 인상한다"""
        self.wage *= self.raise_percentage

    def __str__(self):
        """직원 정보를 문자열로 리턴하는 메소드"""
        return Employee.company_name + " 직원: " + self.name


class Cashier(Employee):
    # 변수 오버라이딩
    raise_percentage = 1.05

    # 메소드 오버라이딩
    def __init__(self, name, wage, number_sold):
    
        # super 함수로 부모 클래스의 메소드를 사용할 땐 self 파라미터가 필요 없다
        Employee.__init__(self, name, wage)
        super().__init__(name, wage)
        
        self.number_sold = number_sold

    def __str__(self):
        return Cashier.company_name + " 계산대 직원: " + self.name

goldstlme = Cashier("민정호", 8000, 4)

print(goldstlme)			# 버거버거 계산대 직원: 민정호
print(goldstlme.name)			# 민정호
print(goldstlme.wage)			# 8000
print(goldstlme.number_sold)		# 4
print(Cashier.raise_percentage)		# 1.05

➡ 다중상속

  • 다중 상속 시, 여러 부모 클래스에 같은 이름의 메소드가 있다면 상속 파라미터 순서에 따라 다른 값이 출력되는 위험성이 있음
    👉 이를 방지하기 위해 부모 클래스끼리 같은 이름의 메소드를 갖지 않도록 하고
    👉 같은 이름의 메소드는 자식 클래스에서 오버라이딩함으로써 해결
# 엔지니어 클래스
class Engineer:
    def __init__(self, favorite_language):
        self.favorite_language = favorite_language

    def program(self):
        print("{}(으)로 프로그래밍합니다.".format(self.favorite_language))


# 테니스 선수 클래스
class TennisPlayer:
    def __init__(self, tennis_level):
        self.tennis_level = tennis_level

    def play_tennis(self):
        print("{} 반에서 테니스를 칩니다".format(self.tennis_level))


# 다중상속된 자식 클래스
class EngineerTennisPlayer(Engineer, TennisPlayer):
    def __init__(self, favorite_language, tennis_level):
        # super()를 이용하면 어느 부모 클래스를 오버라이딩하는지 알 수 없음 
        Engineer.__init__(self, favorite_language)	# 오버라이딩
        TennisPlayer.__init__(self, tennis_level)	# 오버라이딩


# 다중 상속을 받는 클래스의 인스턴스 생성
jahyeon = EngineerTennisPlayer("파이썬", "초급")

# 두 부모 클래스의 메소드들을 잘 물려받았는지 확인
jahyeon.program()		# 파이썬(으)로 프로그래밍합니다.
jahyeon.play_tennis()		# 초급 반에서 테니스를 칩니다

좋은 웹페이지 즐겨찾기