250725 [ Day 15 ] - Python (12)

TaeHyun·2025년 7월 25일

TIL

목록 보기
15/182

시작하며

이번 주는 정말 빠르게 지나간 것 같다. 저번 주 회고 글을 작성한 지 얼마 되지 않은 것 같은데, 벌써 또 일주일이 흘러버렸다. 시간을 더 잘 관리하고 아껴 써야겠다는 생각이 든다.
오늘은 클래스의 상속에 대해 배웠다. 상속은 지금까지 클래스를 공부해온 이유라고 해도 될 만큼, 실제로 많이 사용되고 중요한 개념인 것 같다.

상속과 오버라이딩

상속 (Inheritance)

  • 부모 클래스의 속성과 메서드를 물려받아 새로운 자녀 클래스를 만드는 것
# 부모 클래스
class Animal:
    def __init__(self, name):
        self.name = name

    def bark(self):
        print("동물이 울음 소리를 냅니다.")
# 자녀 클래스
class Dog(Animal):
    pass

d1 = Dog("이름")
d1.bark()
# 동물이 울음 소리를 냅니다.
d1.name
# '이름'

super( )

  • 부모 클래스의 메서드나 생성자를 복사하여 가져올 수 있음
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):
        print("동물이 울음 소리를 냅니다.")
# 자녀 클래스
class Dog(Animal):
    def __init__(self, name, age, species):
        # super : 부모를 가리킴
        # 부모의 함수를 그대로 복제함
        super().__init__(name, age)
        self.species = species

    # 오버라이딩
    def bark(self):
        # 부모의 메서드 복제
        super().bark()
        print("멍멍")

d1 = Dog("이름", 4, "포메라니안")
d1.bark()
# 동물이 울음 소리를 냅니다.
# 멍멍
print(d1.name)
print(d1.age)
print(d1.species)
# 이름
# 4
# 포메라니안

  • 다중 상속
class LivingBeing:
    def __init__(self):
        self.alive = True
    
class Animal(LivingBeing):
    def __init__(self, name, age):
        super().__init__()
        self.name = name
        self.age = age

    def eat(self):
        print(f"{self.name}이 음식을 먹습니다.")

class Dog(Animal):
    def __init__(self, name, age, species):
        super().__init__(name, age)
        self.species = species

    def bark(self):
        print(f"{self.name}{self.species}이며 멍멍 짖어요.")

d1 = Dog("이름1", 10, "비숑")

d1.alive
# True
d1.eat()
# 이름1이 음식을 먹습니다.
d1.bark()
# 이름1은 비숑이며 멍멍 짖어요.

오버라이딩

  • 부모 클래스의 메서드를 자식 클래스에서 동일한 이름으로 다시 정의하는 것
  • 기존 기능을 새로운 방식으로 변경하거나 특화된 동작을 구현할 수 있음
class Shape:
    def __init__(self, sides, base):
        self.sides = sides
        self.base = base

    def printinfo(self):
        print(f"변의 개수 : {self.sides}", end=" ")
        print(f"밑변의 길이 : {self.base}")

    def area(self):
        print("넓이 계산이 정의되지 않았습니다.")

class Rectangle(Shape):
    def __init__(self, sides, base, height):
        super().__init__(sides, base)
        self.height = height
    # 오버라이딩 
    def area(self):
        print(self.base * self.height)

class Triangle(Shape):
    def __init__(self, sides, base, height):
        super().__init__(sides, base)
        self.height = height
    # 오버라이딩
    def area(self):
        print((self.base * self.height) / 2)

r1 = Rectangle(4, 10, 20)
t1 = Triangle(3, 5, 4)

r1.printinfo()
t1.printinfo()
r1.area()
t1.area()
# 변의 개수 : 4 밑변의 길이 : 10
# 변의 개수 : 3 밑변의 길이 : 5
# 200
# 10.0

추상 클래스

  • 직접 인스턴스를 만들 수 없으며, 반드시 자식 클래스에서 구현을 완성해야 하는 클래스
    • 공통적인 구조는 정의하되, 구체적인 동작은 상속받은 클래스에서 구현하도록 강제하는 용도로 사용

추상 클래스의 목적

  • 공통 인터페이스 정의 : 모든 하위 클래스가 따라야 할 메서드 구조 정의
  • 일관성 유지
  • 구현 강제 : 필수 메서드를 구현하지 않으면 오류 발생
  • 코드 재사용 + 설계 명확화
from abc import ABC, abstractmethod

class Animal(ABC):
    @abstractmethod
    def bark(self):
        pass

class Dog(Animal):
    pass

d = Dog()
# 에러 발생 / bark 메서드 구현을 강제

a = Animal()
# Animal 은 추상 클래스이기 때문에 인스턴스 생성 불가
  • abc (Abstract Base Classes) 모듈 사용 → from abc import ABC, abstractmethod
  • ABC를 반드시 상속
  • @abstractmethod 가 붙은 메서드는 반드시 구현

마치며

클래스 파트는 정말 중요한 내용이기 때문에, 세부적인 내용 하나하나를 빠뜨리지 않고 잘 이해할 수 있도록 천천히 진도를 나가다 보니, 막상 정리를 해보면 내용이 그리 많지는 않다.
클래스 자체는 개념과 구조, 사용하는 방법에 대해서는 어느 정도 익힌 것 같지만, 정작 왜 클래스가 필요하고 어떤 상황에서 사용하는지는 아직 직접 경험이 없다 보니 잘 와닿지 않는다.
클래스의 필요성을 실제로 느껴보게 되면, 지금보다 더 효과적으로 활용할 수 있을 것 같다.

NOTION

MY NOTION (Python. Class)

profile
Hello I'm TaeHyunAn, Currently Studying Data Analysis

0개의 댓글