본문 바로가기
Python/개념

Day 7-1. 파이썬 상속

by 사라리24 2024. 3. 18.
SMALL

1. 상속

파이썬에서 상속은 한 클래스의 속성과 메서드를 다른 클래스에 전달하는 기능을 의미합니다. 상속을 사용하면 기존의 코드를 재사용하고 확장할 수 있습니다. 기본적으로 파이썬의 모든 클래스는 object라는 기본 클래스로부터 상속받습니다.

 

  • 기본 클래스 (또는 부모 클래스): 상속의 출발점이 되는 클래스입니다.
  • 파생 클래스 (또는 자식 클래스): 상속을 통해 속성과 메서드를 받는 클래스입니다.

 

 
  class Parent:
      pass

  class Child(Parent):
      pass
 

 

 

 

 
  class Animal:
      def __init__(self, name, age): # 이름, 나이 입력받고 속성에 저장
                                                                     객체가 만들어지면 이름과 나이를 기억
          self.name = name
          self.age = age

      def eat(self, food):          
          print(f'{self.name}{food}를 먹습니다') # self로 변수 name 공유
 

      def sleep(self, hour):
          print(f'{self.name}{hour}시간 동안 잠을 잡니다') # self로 변수 hour 공유
 
 

  animal = Animal('동물', 10)  # 이름과 나이 전송하고 객체 생성
  animal.eat('먹이')                # eat메소드 food 넣어서 실행
  animal.sleep(14)                 # sleep메소드 hour 넣어서 실행
 
동물는 먹이를 먹습니다
동물는 14시간 동안 잠을 잡니다

 

 
  class Dog(Animal):           # Animal 클래스를 상속
      pass
 

  # Rucy = Dog()             # 에러남, 생성자 넣어줘야 함
                                           # Animal 클래스의 생성자를 상속받았기 때문에
                                           생성자 매개변수를 전달해야 합니다.

 
  Rucy = Dog('루시', 14)
  Rucy.eat('사료')
  Rucy.sleep(10)
 

 

루시는 사료를 먹습니다
루시는 10시간 동안 잠을 잡니다

 

 

 

  • 클래스 상속 시 생성자 호출 순서
    1. 자식 클래스(child class)의 생성자가 먼저 호출됩니다. (빈 생성자)
    2. 자식 클래스의 생성자에서 부모 클래스(parent class)의 생성자를 호출해야 합니다. 이를 위해 super() 함수를 사용합니다. super() 함수는 현재 클래스의 부모 클래스를 참조하며, 부모 클래스의 생성자를 호출할 수 있습니다.
    3. 부모 클래스의 생성자가 호출됩니다.
    4. 부모 클래스의 생성자가 실행을 마치면 자식 클래스의 생성자로 돌아가 자식 클래스의 생성자 코드가 실행됩니다.
  
  class Parent:
      def __init__(self):
          print('부모 클래스의 생성자 호출')
 
 

  class Child(Parent):
      def __init__(self):
          print('Child 클래스 생성자 호출')
          super().__init__() # 부모 클래스의 생성자를 호출
          print('자식 클래스의 생성자 호출')
 
 

  child = Child()
 
Child 클래스 생성자 호출
부모 클래스의 생성자 호출
자식 클래스의 생성자 호출

 

 

 

2. object 클래스

  object 파이썬의 모든 클래스의 기본 클래스입니다.
object 
클래스는 파이썬에서 모든 객체의 기본적인 동작과 특성을 정의합니다.

 

 
 
     class MyClass:
        pass
 

    # 위의 코드는 다음과 동일합니다.
    # 자동으로 상속받음
 
 
    class MyClass(object):
      pass
 
 
  • object 클래스는 모든 클래스에서 상속을 받음: 파이썬에서 모든 것은 객체입니다. 숫자, 문자열, 리스트, 사용자 정의 객체 등이 모두 객체입니다. 그리고 이 모든 객체의 기본 클래스는 object 클래스입니다. "변수가 가리키는 객체가 object의 인스턴스라는 것"을 기억하는 것이 좋습니다.
  • object가 상속해주는 메서드: object 클래스는 여러 가지 기본적인 메서드를 제공합니다. 이 메서드들은 대부분의 파이썬 객체에서 사용할 수 있습니다. 그렇지만 모든 객체가 이 메서드들의 기능을 모두 활용하는 것은 아닙니다. object에서 제공하는 메서드들의 기본 구현은 대부분의 객체에 적합하지 않을 수 있습니다. 따라서 사용자 정의 클래스 또는 다른 내장 클래스에서 이러한 메서드를 오버라이드하여 원하는 동작을 구현하게 됩니다. 이러한 메서드는 일반적으로 직접 호출하기보다는 해당 연산자나 함수를 사용할 때 암시적으로 호출됩니다.

 

 

3. 메서드 오버라이딩

  메서드 오버라이딩(Method Overriding)은 객체 지향 프로그래밍에서 중요한 개념  하나로서브 클래스(자식 클래스)에서 슈퍼 클래스(부모 클래스)의 메서드를 재정의하는 것을 의미합니다오버라이딩을 사용하면서브 클래스에서 상속받은 메서드의 동작을 변경하거나 확장할  있습니다.

 

  • 서브 클래스에서 슈퍼 클래스의 메서드 재정의: 서브 클래스는 슈퍼 클래스에서 상속받은 메서드와 동일한 이름의 메서드를 가질 수 있습니다. 이때, 서브 클래스에서의 메서드 구현이 슈퍼 클래스의 메서드를 "오버라이드"합니다.
  • 메서드의 시그니처: 오버라이딩할 때, 메서드의 이름은 물론이고 매개변수의 타입과 개수도 일치해야 합니다. 반환 타입은 일치할 필요는 없지만, 일반적으로 같게 유지하는 것이 좋습니다.
  
  class Animal:
      def __init__(self, name, age):
          self.name = name
          self.age = age

      def eat(self, food):
          print(f'{self.name}{food}를 먹습니다')

      def sleep(self, hour):
          print(f'{self.name}{hour}시간 동안 잠을 잡니다')

  class Dog(Animal):
      def run(self):
          print(f'{self.name}는 달립니다')

      def eat(self, food):  # 메소드 오버라이딩 (부모메소드를 변경)
          print(f'{self.name}{food}를 아주~ 맛있게 먹습니다')

      def superEat(self, food):
          super().eat(food) # 부모 생성자가 호출되고 부모의 메소드를 실행
 
 

  Rucy = Dog('루시', 12)
  Rucy.eat('사료')
  Rucy.run()
 
 

   animal = Animal('동물', 10)
  animal.eat('먹이') # 부모 클래스의 메소드가 출력
  # animal.run()      # 에러: 부모클래스는 자식 클래스의 메소드를 사용할 수 없음
                                          부모 클래스는 자식 클래스를 알 수 없습니다.
 
 


루시는 사료를 아주~ 맛있게 먹습니다
루시는 달립니다
루시는 사료를 먹습니다
동물는 먹이를 먹습니다

 

※ super() 메소드

 

  super()는 파이썬의 내장 함수로서, 상속과 관련된 작업을 수행할 때 사용됩니다. 특히, 자식 클래스에서 부모 클래스의 메서드를 호출할 때 사용됩니다. super()의 주요 목적은 자식 클래스에서 부모 클래스의 메서드를 오버라이드(재정의)하면서도 그 오버라이드된 메서드 내에서 부모 클래스의 원본 메서드를 호출하는 것입니다.

 

1. 기본적인 사용

  
  class Parent:
      def hello(self):
          print("Hello from Parent class")

  class Child(Parent):
      def hello(self):
          super().hello()
          print("Hello from Child class")

  c = Child()
  c.hello()
 
Hello from Parent class
Hello from Child class

 

2. __init__ 메서드에서의 사용

  
  class Parent:
      def __init__(selfvalue):
          self.value = value

  class Child(Parent):
      def __init__(selfvaluechild_value):
          super().__init__(value)
          self.child_value = child_value

  c = Child(10, 20)
  print(c.value)       
  print(c.child_value) 
 
10
20

 

 

4. 다중상속

 

  다중 상속은 클래스가 둘 이상의 부모 클래스로부터 상속을 받는 기능을 의미합니다. 파이썬은 다른 많은 객체 지향 언어와 달리 다중 상속을 지원합니다. 다중 상속을 사용하면 코드의 재사용성을 향상시킬 수 있지만, 동시에 복잡성이 높아지기 때문에 주의해야 합니다.

 

  
  class Parent1:
      pass

  class Parent2:
      pass

  class Child(Parent1Parent2):
      pass
 

 

 

  
  class Animal:
     def __init__(selfnameage):
          self.name = name
          self.age = age
  
      def eat(selffood):
          print(f'{self.name}는 {food}를 먹습니다')

      def sleep(selfhour):
          print(f'{self.name}는 {hour}시간 동안 잠을 잡니다')

  class Human:
      def __init__(selfnameage):
          self.name = name
          self.age = age

      def study(selfhour):
          print(f'{self.name}는 {hour}시간 동안 공부를 합니다')

  class KimApple(AnimalHuman): # 다중상속
      pass

  kim = KimApple('김사과', 20)

  kim.eat('밥')
  kim.study(2)
  kim.study(8)
 
  print(KimApple.mro())


김사과는 밥를 먹습니다
김사과은(는) 2시간 동안 공부를 합니다.
김사과는 8시간 동안 잠을 잡니다

[<class '__main__.kimapple'>, <class '__main__.animal'>, <class '__main__.human'>, <class 'object'>].</class 'object'></class '__main__.human'></class '__main__.animal'></class '__main__.kimapple'>

 

 다중 상속의 문제

 

  다중 상속을 사용할 때 가장 대표적인 문제는 다이아몬드 문제입니다. 이 문제는 두 개 이상의 부모 클래스가 동일한 조상 클래스를 가질 때 발생합니다. 이것을 해결하기 위해 MRO를 확인해야 합니다.

  • 메서드 해석 순서 (Method Resolution Order, MRO):
    - 파이썬에서는 위와 같은 다이아몬드 문제를 해결하기 위해 MRO를 사용합니다.
       MRO는 클래스의 메서드를 찾을 때 사용하는 규칙입니다.
    - D 클래스의 경우 MRO는 [D, B, C, A]로 결정됩니다.
      따라서 d.hello()를 호출하면 B 클래스의 hello() 메서드가 실행됩니다.
  • C3 선형화 알고리즘
    - 파이썬의 다중상속에서 메서드 해결순서(Method Resoultion, MRO)를 계산하는데 사용되는 알고리즘
    - 복잡한 상속 구조에서 메서드를 호출 순서를 명확하게 결정하기 위해 고안된 알고리즘
 
 
  print(Child.mro())
 
 
[<class '__main__.Child'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]

 

 

  
 
  class Base:
      def hello(self):
          print("Hello from Base class")

  class A(Base):
      def hello(self):
          print("A의 Hello")
          super().hello()
          print("Hello from A class")

  class B(Base):
      def hello(self):
          print("A의 Hello")
          super().hello()
          print("Hello from B class")

  class Child(A, B):
      def hello(self):
          print("Child의 Hello")
          super().hello()
          print("Hello from Child class")

  child = Child()
  child.hello()
  print(Child.mro())
 
Child의 Hello
A의 Hello
A의 Hello
Hello from Base class
Hello from B class
Hello from A class
Hello from Child class
[<class '__main__.Child'>, <class '__main__.A'>, <class '__main__.B'>, <class '__main__.Base'>, <class 'object'>]

 

 

 

 
  print(D.mro())
 
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

 

  
  class A:
     def hello(self):
        print("Hello from A")

  class B(A):
      def hello(self):
          print("Hello from B")

  class C(A):
      def hello(self):
          print("Hello from C")

  class D(B, C):
      pass

  d = D()
  d.hello()  # 어떤 hello() 메서드가 호출될까?
 
Hello from B



'Python > 개념' 카테고리의 다른 글

Day 7-3. 파이썬의 예외처리  (0) 2024.03.18
Day 7-2. 파이썬 스페셜(매직) 메소드  (0) 2024.03.18
Day 6-3. 객체지향과 클래스  (0) 2024.03.18
Day 6-2. 콜백함수와 람다함수  (0) 2024.03.15
Day 6-1. 변수의 범위  (0) 2024.03.15