본문 바로가기

Python/Basic

[파이썬] 클래스

클래스란?

클래스는 객체를 표현하기 위한 틀 또는 청사진으로, 특정한 개념이나 모양을 가진 객체를 생성하는데 사용됩니다. 

객체 지향 프로그래밍 언어는 이러한 클래스와 객체를 중심으로 프로그래밍하는 패러다임을 가지고 있습니다. 여기서 클래스는 속성과 메소드로 구성됩니다.

-속성 (Attributes): 객체의 상태나 특징을 나타내는 데이터입니다. 이는 클래스 내부에 정의된 변수로 나타납니다.

예를 들어, 게임 캐릭터의 경우 힘, 민첩성, 체력 등이 속성에 해당합니다.

-메소드 (Methods): 객체의 동작이나 행위를 나타내는 코드 블록입니다. 이는 클래스 내부에 정의된 함수로 나타납니다.

예를 들어, 게임 캐릭터의 경우 공격, 이동, 스킬 사용 등이 메소드에 해당합니다.

예시로 게임의 직업 클래스를 생각해보겠습니다. 각 직업(전사, 마법사, 궁수 등)은 고유한 속성(힘, 민첩성, 지력, 운, 물리공격력, 마법공격력)을 가지며, 각 직업은 고유한 행동을 하는 메소드(찌르기, 파이어볼, 활쏘기 등)를 가집니다.

이러한 클래스의 구조를 통해 객체 지향 프로그래밍은 현실 세계의 객체들을 모델링하여 프로그램을 개발하는데 매우 유용합니다. 클래스를 활용할 시 코드의 재사용성과 유지보수성이 높아지며, 복잡한 시스템을 구축하기에 용이해집니다.

 

 

클래스 간의 관계, 상속과 포함

 

상속이란?

상속은 한 클래스가 다른 클래스의 속성과 메소드를 물려받아 사용하는 것을 말합니다. 

상속을 통해 기존 클래스를 확장하거나 수정하여 새로운 클래스를 만들 수 있습니다. 

이때, 기존 클래스는 부모 클래스(parent class)이고, 새로운 클래스는 자식 클래스(child class)입니다.

예를 들어, '동물' 클래스가 있을 때, '고양이' 클래스와 '개' 클래스는 '동물' 클래스를 상속받아 공통된 특성을 가지게 됩니다. 이후에 각각의 클래스는 자신만의 추가적인 속성이나 메소드를 정의할 수 있습니다.

상속은 코드의 재사용성을 높이고, 계층적 구조를 갖는 객체 모델을 구성할 때 유용합니다.

 

# Animal 클래스 정의 (부모 클래스)
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        pass

# Dog 클래스 정의 (Animal 클래스를 상속받음)
class Dog(Animal):  # 여기서 Animal 클래스를 상속받음
    def speak(self):
        return "멍멍!"

# Cat 클래스 정의 (Animal 클래스를 상속받음)
class Cat(Animal):  # 여기서 Animal 클래스를 상속받음
    def speak(self):
        return "야옹!"

dog = Dog("멍멍이")
cat = Cat("야옹이")

# 이름과 소리 출력
print(dog.name, dog.speak())  # 출력: 멍멍이 멍멍!
print(cat.name, cat.speak())  # 출력: 야옹이 야옹!

위 코드에서 Animal 클래스는 모든 동물의 기본적인 특성을 정의합니다. 그리고 Dog 클래스와 Cat 클래스는 각각 Animal 클래스를 상속받아 speak 메소드를 오버라이딩하여 개와 고양이의 소리를 반환합니다.

 

 

 

포함이란?

포함은 한 클래스가 다른 클래스의 객체를 포함하는 것을 의미합니다.

이는 한 클래스가 다른 클래스의 인스턴스를 변수로 가지는 것을 말합니다. 이를 통해 두 클래스 간의 느슨한 결합(loose coupling)을 유지하면서 기능을 확장할 수 있습니다.

예를 들어, '자동차' 클래스가 있을 때, '엔진' 클래스의 객체를 자동차 클래스 내부에 포함시켜서 자동차가 엔진의 기능을 사용할 수 있게 만들 수 있습니다.
포함은 한 클래스가 다른 클래스를 포함하는 것으로, 두 클래스 간의 관계를 더 유연하게 만들어줍니다. 

이는 클래스 간의 결합도를 낮추고 코드의 재사용성을 높일 수 있습니다.

 

# Engine 클래스 정의 (포함될 클래스)
class Engine:
    def start(self):
        return "엔진 시동 걸기"

    def stop(self):
        return "엔진 정지"

# Car 클래스 정의 (Engine 클래스를 포함)
class Car:
    def __init__(self):
        self.engine = Engine()  # 여기서 Engine 클래스를 포함

    def drive(self):
        return self.engine.start()

    def park(self):
        return self.engine.stop()

my_car = Car()

# 엔진을 이용하여 차량 조작
print(my_car.drive())  # 출력: 엔진 시동 걸기
print(my_car.park())   # 출력: 엔진 정지

 

위 코드에서 Engine 클래스는 엔진의 기능을 정의합니다. 그리고 Car 클래스는 Engine 클래스의 인스턴스를 포함하고 있습니다. Car 클래스는 drive 메소드를 호출할 때 엔진의 시동을 거는 기능을 수행하고, park 메소드를 호출할 때 엔진을 정지시키는 기능을 수행합니다.

 

 

포함관계 예시1)

로또 번호 생성 프로그램

import random

class LottoBall:
    def __init__(self, num):
        self.num = num  # 로또 번호를 나타내는 속성

class LottoMachine:
    def __init__(self):
        self.ballList = []  # 로또 공을 담을 리스트를 초기화합니다.

        # 1부터 45까지의 번호를 가지는 로또 공을 생성하고 리스트에 추가합니다.
        for i in range(1, 46):
            self.ballList.append(LottoBall(i))  # 포함 관계: LottoBall 클래스를 포함합니다.

    def selectBall(self):
        # 번호를 섞기 전
        print("로또 번호 (섞기 전):", end=' ')
        for a in range(45):
            print(self.ballList[a].num, end=' ')
        print()

        # 번호를 섞습니다.
        random.shuffle(self.ballList)  # 리스트의 순서를 무작위로 섞습니다.

        # 번호를 섞은 후
        print("로또 번호 (섞은 후):", end=' ')
        for a in range(45):
            print(self.ballList[a].num, end=' ')

        # 섞인 공 중에서 앞에서부터 6개를 선택하여 반환합니다.
        return self.ballList[0:6]

class LottoUI:
    def __init__(self):
        self.machine = LottoMachine()  # 포함 관계: LottoMachine 클래스를 포함합니다.

    def playLotto(self):
        input("로또 볼을 뽑으려면 엔터키를 누르세요.")
        selectedBalls = self.machine.selectBall()

        print("\n선택된 로또 번호:")
        for ball in selectedBalls:
            print('%d' % (ball.num))


if __name__ == '__main__':
    LottoUI().playLotto()  # 프로그램 실행 시 LottoUI 객체를 생성하고 playLotto 메소드를 호출합니다.

* 클래스 LottoMachine에서 ballList는 해당 클래스의 속성(attribute)으로 정의되어 있으며,

속성을 초기화하기 위해 __init__ 메소드를 사용하며, 이 메소드는 클래스가 인스턴스화될 때 자동으로 호출됩니다.
따라서 LottoMachine 클래스의 __init__ 메소드에서 self.ballList를 초기화하고 있기 때문에 별도의 파라미터나 인수를 받아올 필요가 없습니다. self는 현재 인스턴스를 나타내며, self.ballList는 그 인스턴스의 속성으로 정의됩니다.

 

포함관계 예시2)

커피 자판기 프로그램

class CoinIn:
    def __init__(self, coffee):
        self.coffee = coffee

    def culc(self, coin, cupCount):
        total_cost = cupCount * self.coffee
        if coin >= total_cost:
            change = coin - total_cost
            print('커피 {}잔과 잔돈 {}원'.format(cupCount, change))
        else: 
            print('요금이 부족합니다')

class Machine:
    def __init__(self):
        self.coffee = 200
        self.coin_in = CoinIn(self.coffee)  # 포함 관계: CoinIn 클래스를 포함합니다.

    def ShowData(self, coin, cupCount):
        # CoinIn 객체의 culc 메소드를 호출합니다.
        self.coin_in.culc(coin, cupCount)

if __name__ == '__main__':
    coin = int(input("동전을 입력하세요: "))
    cupCount = int(input("몇 잔을 원하세요: "))
    Machine().ShowData(coin, cupCount)

 

포함관계를 만드는 이유는 Machine 클래스가 CoinIn 클래스의 기능을 사용하기 위해서입니다. 

CoinIn 클래스는 커피값을 계산하고 출력하는 역할을 하고 있습니다. 

Machine 클래스가 CoinIn 클래스를 포함하게 되면, Machine 클래스에서 CoinIn 클래스의 객체를 생성하여 self.coin_in 속성으로 가질 수 있습니다. 이렇게 함으로써 Machine 클래스는 CoinIn 클래스의 기능을 사용할 수 있습니다.