본문 바로가기
공부 & 프로젝트/파이썬

[파이썬] Class : init, 메소드, 상속, 다중상속, 메소드 오버라이딩

by donnanoa82 2025. 10. 15.

하기의 링크인 '나도코딩'의 파이썬 수업 중 Class 부분 정리하겠습니다. 

https://www.youtube.com/watch?v=kWiCuklohdY

 


Class: 

def 함수를 만들어서 반복적인 코딩 작업을 없앨 수 있음 =  같은 구조를 가진 여러 개체를 쉽게 생성 가능 (복붙이 아니라, 재사용 가능한 틀로 만드는 것!)

붕어빵 틀과 같다고 보면 됨. 틀을 가지고 붕어빵 재료를 넣어 붕어빵을 만들 수 있음

Init:

__init__()**는 **“생성자(constructor)”**라고 불림
이 함수는 객체(인스턴스)가 만들어질 때 자동으로 실행되는 초기 설정 함수

  • __init__ =  객체가 만들어질 때 자동으로 실행
  • self.name = name처럼 객체 내부에 변수를 저장하는 역할
  • 즉, “이 객체가 어떤 값을 가질지”를 초기화(Initialize) 하는 함수
class Person:
    def __init__(self, name, age):
        self.name = name   # 인스턴스 변수 설정
        self.age = age

 

  • self는 현재 만들어지는 객체 자신을 가리킴
  • 즉, “이 객체의 속성”을 설정하거나 접근할 때 항상 self.를 붙여야 함

 

class Unit:
    def __init__ (self, name, hp, damage):
        self.name = name
        self.hp = hp
        self.damage = damage
        print(f"{self.name} 유닛이 생성되었습니다.")
        print(f"체력은 {self.hp}, 공격력은 {self.damage}입니다.")

Marine = Unit("마린", 45, 5)
#여기서 class unit을 불러오고 싶다면, 
print(Marine.name)    #값: "마린"

 

 

메소드

메서드(Method) = 클래스 안에서 정의된 함수(function)

(위 코드에서 설명되어있지만, Marine = Unit("마린", ~~~)을 지정한 상태에서 Marine.name으로 할 경우, "마린"값을 생성

  => 메서드는 클래스 안에서 객체.메서드이름을 통해 값을 불러들일 수 있음

구분  함수(Function)  메서드(Method)
정의 위치 클래스 밖 클래스 안
호출 방식 함수이름() 객체.메서드이름()
첫 번째 매개변수 자유롭게 사용 self (객체 자신을 의미)
#일반 유닛
class Unit: 
    def __init__ (self, name, hp, damage):
        self.name = name
        self.hp = hp
        self.damage = damage
        print(f"{self.name} 유닛이 생성되었습니다.")
        print(f"체력은 {self.hp}, 공격력은 {self.damage}입니다.")
        


#공격 유닛
class AttackUnit: 
    def __init__ (self, name, hp, damage):
        self.name = name
        self.hp = hp
        self.damage = damage
        print(f"{self.name} 이 생성되었습니다. \n 체력은 {self.hp} 공격력은 {self.damage} 입니다.") 
        
    def attack (self, location):
        print(f"{self.name}이 {location} 방향으로 공격하였습니다. [공격력: {self.damage}]")
    
    def damaged (self, damage):
        print(f"{self.name} 이 {damage} 데미지 만큼 공격받았습니다. ")
        self.hp -= damage
        print(f"{self.name}의 현재 체력은 {self.hp}입니다.")
        if self.hp <= 0:
            print(f"{self.name}이 파괴되었습니다.")
            

#파이어뱃 : 공격 유닛, 화염방사기
firebat1 = AttackUnit("파이어벳", 50, 16)
firebat1.attack("5시")

#공격 2번 받는다고 가정
firebat1.damaged(25)
firebat1.damaged(25)

 

상속

기존 클래스(부모 클래스, 부모 설계도)의 속성과 메서드를 새로운 클래스(자식 클래스)가 물려받는 것

즉, “비슷한 기능을 새로 만들지 않고, 기존 것을 물려받아 재사용하는 방법”

 

예시 :

Class Unit 의 내용을 상속 받아서 AttackUnit을 만드는 것 

damage 공격력 없는 유닛 존재 => Class Unit에서 'damage'부분 제거 후, 공격 유닛이 상속받아 사용 

#일반 유닛
class Unit: 
    def __init__ (self, name, hp):
        self.name = name
        self.hp = hp
        print(f"{self.name} 유닛이 생성되었습니다.")
        
#공격 유닛
class AttackUnit(Unit):                        #Unit class 상속받음
    def __init__ (self, name, hp, damage):
        Unit.__init__ (self, name, hp)         #Unit class에는 damage 부분이 없으므로 아래에 self.damage부분 추가
        self.damage = damage

 

 

다중상속

상속란에 여러 클래스 넣는 것 

 

예시 코드를 설명하자면, 

FlyableAttackUnit < (1) AttackUnit (2) Flyable

(1) AttackUnit < Unit

(2) Flayble

#날 수 있는 기능을 가진 클래스
class Flyable: 
    def __init__ (self, flying_speed):
        self.flying_speed = flying_speed

    def fly (self, name, location):
        print(f"{name} : {location} 방향으로 날아갑니다. [속도 {self.flying_speed}]")
        
#공중 공격 유닛 클래스
class FlyableAttackUnit (AttackUnit, Flyable):    #다중 상속
    def __init__ (self, name, hp, damage, flying_speed):
        AttackUnit.__init__(self,name, hp,damage)
        Flyable.__init__(self, flying_speed)
        
"===================================================="
#발키리 : 공중 공격 유닛, 한번에 14발 미사일 발사
valkyrie = FlyableAttackUnit("발키리", 200, 6, 5)
valkyrie.fly(valkyrie.name, "3시")

 

 

메소드 오버라이딩

부모 클래스의 메서드를 자식 클래스에서 “같은 이름으로 다시 정의”하는 것
즉, 물려받은 기능을 자식에게 맞게 바꿔 쓰는 것

class Parent:
    def say_hello(self):
        print("안녕, 나는 부모야!")

class Child(Parent):
    def say_hello(self):  # 부모의 메서드를 다시 정의 (오버라이딩)
        print("안녕, 나는 자식이야!")

 

위 코드를 보면 부모의 메서드(say_hello)를 다시 정의해서 사용 

#일반 유닛
class Unit: 
    def __init__ (self, name, hp, speed):           #지상 유닛의 속도 추가
        self.name = name
        self.hp = hp
        self.speed = speed
    def move (self, location):
        print("[지상 유닛 이동]")
        print(f"{self.name} : {location} 방향으로 이동합니다. [속도 : {self.speed}]")
        
 
class AttackUnit(Unit): 
    def __init__ (self, name, hp, damage,speed):
        Unit.__init__ (self, name, hp, speed)
        self.damage = damage
        print(f"{self.name} 이 생성되었습니다. \n 체력은 {self.hp} 공격력은 {self.damage} 입니다.")
        
#날 수 있는 기능을 가진 클래스
class Flyable: 
    def __init__ (self, flying_speed):
        self.flying_speed = flying_speed

    def fly (self, name, location):
        print(f"{name} : {location} 방향으로 날아갑니다. [속도 {self.flying_speed}]")
#공중 공격 유닛 클래스
class FlyableAttackUnit (AttackUnit, Flyable):
    def __init__ (self, name, hp, damage, flying_speed):
        AttackUnit.__init__(self,name, hp,damage, 0)    #지상 스피드 = 0
        Flyable.__init__(self, flying_speed)

"======================================================="
#벌처 : 지상 유닛, 기동성 좋음
vulture = AttackUnit("벌쳐", 80, 10, 20)

#배틀크루저 : 공중 유닛, 체력도 굉장히 좋음, 공격력도 좋음
battlecruiser = FlyableAttackUnit ("배틀크루저", 500, 25, 3)

vulture.move("1시")
battlecruiser.fly ("배틀크루저", "5시")

 

매번 지상 유닛인지 공중 유닛인지 확인해서 move/ fly를 써야하는 것이 번거로움. 

vulture.move("1시")
battlecruiser.fly ("배틀크루저", "5시")

 

따라서, FlyableAttackUnit 클래스 아래에 move 함수를 넣어서 move라는 이름으로 함께 사용 

이때 self.fly를 재정의 하여 move 함수 생성

#공중 공격 유닛 클래스
class FlyableAttackUnit (AttackUnit, Flyable):
    def __init__ (self, name, hp, damage, flying_speed):
        AttackUnit.__init__(self,name, hp,damage, 0)    #지상 스피드 = 0
        Flyable.__init__(self, flying_speed)
    def move (self, location):                      #추가 
        print("[공중 유닛 이동]")
        self.fly(self.name, location)

 

=> 그렇게 되면 move라는 동일한 메소드 이름을 사용 가능

vulture.move("1시")
battlecruiser.move ("5시")

#답
[지상 유닛 이동] 벌쳐 : 1시 방향으로 이동합니다. [속도 : 20]
[공중 유닛 이동] 배틀크루저 : 5시 방향으로 날아갑니다. [속도 3]

 

 

Pass

아무것도 하지 않음

일단 완성된 것 처럼 보여지고, 넘어감

 

나중에 코드 작성할 때 “여기 함수 만들 예정”이라는 자리 표시용으로 쓸 수 있음

class BuildingUnit(Unit):
    def __init__(self, name, hp, location):
        pass
#서플라이 디폿 : 건물, 1개 건물 = 8 유닛
supply_depot = BuildingUnit("서플라이디폿", 500, "7시")

 

Super

class BuildingUnit(Unit):
    def __init__(self, name, hp, location):
        Unit.__init__(self, name, hp, 0)
        self.location = location

이렇게 사용 가능하지만, 아래와 같이 super을 사용해서도 사용 가능

****super 사용 시, super뒤에 () + self 삭제 ***

class BuildingUnit(Unit):
    def __init__(self, name, hp, location):
        super().__init__(name, hp, 0)
        # Unit.__init__(self, name, hp, 0)    #참고용
        self.location = location

 

다중 상속에서는 문제 발생

: 아래 코드에서 확인 가능

일단, Unit, Flyable class 생성

class Unit:
    def __init__ (self):
        print("Unit 생성자")
class Flyable:
    def __init__ (self):
        print("Flyable 생성자")

 

FlyableUnit을 Unit, Flyable class 상속하고, super를 사용했을 때, 

  상속되는 class의 맨 처음의 class에만 작용됨 : 아래에서 확인 가능

class FlyableUnit (Unit, Flyable):
    def __init__ (self):
        super().__init__()

dropship = FlyableUnit()

##값: Unit 생성자
class FlyableUnit (Flyable, Unit):
    def __init__ (self):
        super().__init__()

dropship = FlyableUnit()

##값: Flyable 생성자

 

따라서, 다중상속에서는 super를 사용하지 않고 그대신 명시적으로 표기 필요 = 아래와 같이

 

class FlyableUnit (Flyable, Unit):
    def __init__ (self):
        Unit.__init__(self)
        Flyable.__init__(self)