본문 바로가기

파이썬

[ 코랩과 파이썬 ] 17. python 클래스(class) 오버라이딩(overriding)과 super() 함수

반응형

1. class 클래스

 

클래스(class)는 파이썬에서 반드시 사용해야만 하는 함수는 아니다. 클래스는 좀 복잡한 개념이기는 하지만 단순히 설명하면, 정의된 함수(def) 여러 개를 한 번에 실행할 수 있도록 하나로 묶어 놓는 함수라고 이해하면 된다. 그래서 클래스를 쓰지 않고 함수를 def로 여러 개 정의해도 완성된 스크립트를 작성할 수 있다.

 

예를 들어 게임 캐릭터를 만들 때 모든 캐릭터가 공격력, 방어력, 체력을 공통으로 가지고 있다면, 이들을 각각 def로 정의할 수도 있지만, 클래스를 사용하면 한 번에 캐릭터가 생산된다.

 

클래스는 틀이나 설계도라고 할 수 있다. 설계도나 틀의 역할을 하는 클래스로 만들어진 것들을 객체(object) 혹은 인스턴스(instance)라고 한다. 객체는 속성(attributes)과 기능(methods)을 갖는다.

 

스타크래프트 게임에서 마린을 생산한다고 할 때 ‘마린’이라는 이름과 ‘육군’, ‘체력’, ‘공격력’ 등의 속성을 갖고, ‘공격’, ‘이동’ 등의 메서드를 갖는다.

 

클래스를 사용하지 않고 def 함수를 이용해 속성과 메서드를 각각 정의한다면, 마린을 하나 뽑을 때마다 def 함수를 시행시켜야 하고, 이름도 마린1, 마린2…로 모두 따로 저장해야 한다. 그렇지 않고 같은 변수에 저장하면 모두 덮어 쒸어져 하나로 된다.

 

반면 클래스 명령문을 사용하면 클래스가 틀의 역할을 하므로 같은 같은 변수에 저장해도 똑같은 마린이 계속 생산된다.

 

클래스의 표현 방식은 다음과 같다.

class 클래스 명:                    # 클래스명은 일반적으로 첫 자는 대문자로 씀

   def (매직)메서드(self, ...):    # self(=클래스명)는 클래스 명을 받아서 속성을 지정

       실행문

 

클래스 명은 일반적으로 첫 글자를 대문자로 사용한다. 그리고 함수 정의(def)를 동반하는데 이때 self라는 매개변수를 이용한다. self는 클래스 받아서 클래스에 속성을 붙이기 위해 사용한다. 예를 들어 class Wizard라고 클래스를 생성했을 때, 이 클래스에 name이라는 속성을 붙이고 싶다면 Wizard.name 대신에 self.name 을 사용한다.

또한 클래스는 매직 메서드와 함께 사용하게 된는데, 매직 메서드는 클래스가 파이썬에서 제공하는 내장함수, 연산자 등과 쉽게 연결되도록 제공해 주는 특별한 함수이다. "__" 로 시작해서 "__"로 끝나며 매직 메서드의 종류와 기능은 다음과 같다.

 

매직 메서드 설명 형식
__init__ 클래스 변수(인스턴스)가 생성될 때 호출되는 함수 __init__(self)
__str__ 클래스 변수를 출력할 때 또는 문자열로 변환할 때 호출되는 함수 __str__(self)
__del__ del() 함수의 인자 값으로 사용될 때 호출되는 함수 __del__(self)
__eq__ 클래스 변수가 비교 연산자와 함께 사용될 때 호출되는 함수 ​ __eq__(self, other)
__ne__ __ne__(self, other)
__lt__ __lt__(self, other)
__gt__ __gt__(self, other)
__le__ __le__(self, other)
__ge__ __ge__(self, other)
__add__ 클래스 변수가 사칙연산과 함께 사용될 때 호출되는 함수     __add__(self, other)
__sub__ __sub__(self, other)
__mul__ __mul__(self, other)
__div__ __div__(self, other

 

 

온라인 게임에서 캐릭터를 찍어 내는 클래스를 만들어 보자. 기본적으로 모든 케릭터는 이름(name), 체력(hp), 이동속도(speed)를 갖는다고 하자. 농부(farmer)를 만들어서 2시 방향으로 이동시켜보자.

 

class Character:

  def __init__(self, name, hp, speed):
    self.name = name
    self.hp = hp
    self.speed = speed
    print(f"{self.name}가 생성되었습니다.")

  def move(self, location):
    print(f"{self.name}가 {location} 방향으로 이동합니다.")

 

Character 클래스는 이름(name), 체력(hp), 이동속도(speed)라는 세 가지 속성과 move라는 하나의 메서드를 갖는다. __init__는 메서드는 클래스의 새 인스턴스를 생성할 때 호출하는 초기화 메서드이다. 해당 인스턴스의 name, hp, speed를 초기화한다.

 

Character 클래스에서 농부(farmer)를 생성하기 위해 name = ‘farmer’, hp=100, speed=30 값을 입력해 함수를 호출하듯이 사용한다. 생성한 farmer를 move 메서드를 이용해 2시 방향으로 이동시켜보자.

 

farmer =  Character("farmer", 100, 30)  # farmer가 생성되었습니다
farmer.move("2시")      # farmer가 2시 방향으로 이동합니다.

 

이번에는 체력(hp: 50), 속도(speed=10)인 간호사(”nurse”)를 생성해서 5시 방향으로 이동시켜 보자.

 

nurse =  Character("nurse", 200, 50)  # nurse가 생성되었습니다
nurse.move("5시")      # nurse가 2시 방향으로 이동합니다.

 

 

2. 클래스 상속

 

클래스를 상속할 수 있다. 클래스를 상위( super)와 하위(sub) 클래스로 나누어서 하위 상위 클래스에서 정의된 속성과 메서드를 하위 클래스가 그대로 물려받는 것을 상속이라고 한다. 이때 상위 클래스를 부모(parant), 기초(basic) 클래스라고 하고, 하위 클래스를 자식(child), 파생(derived) 클래스라고 한다.

 

하위 클래스가 상위 클래스를 그대로 받기 때문에 새로운 코드를 작성할 필요가 없고 클래스를 계층 구조로 구분할 수 있어서 코드를 효율적으로 관리할 수 있다.

 

class 클래스명 A: # 부모(Pararent), 상위(Super), 기초(Base) 클래스

   실행문

class 클래스명 B(클래스명 A) # 자식(Child), 하위(Sub), 파생(Derived) 클래스

   실행문

 

이번에는 캐릭터들이 가지고 있는 기본 속성에 공격력이라는 속성을 추가해 공격 케릭터를 만들어 보자.

 

class Character:                        # 부모 클래스

  def __init__(self, name, hp, speed):  # 속성 정의 및 초기화
    self.name = name                    # self(Character)의 속성값으로 저장
    self.hp = hp
    self.speed = speed
    print(f"{self.name}가 생성되었습니다.")

  def move(self, location):             # 이동 함수 정의: Character 클래스의 메서드
    print(f"{self.name}이 {location} 방향으로 이동합니다.")

class Attack(Character):                 # 자식 클래스
  def __init__(self, name, hp, speed, attack):      # 속성 정의 및 초기화
    Character.__init__(self, name, hp, speed)       # 부모 클래스 속성 상속
    self.attack = attack                            # 자녀 클래스 속성 저장

  def move_attack(self, location):                  # 이동 공격 함수 정의: Attack 클래스의 메서드
    print(f"{self.name}가 {location}방향으로 공격력 {self.attack}으로 공격했습니다")

 

위의 예제에서 Character는 부모 클래스이고, Attack은 자식 클래스이다. Attack 클래스는 name, hp, speed, attack이라는 4가지 속성을 가지는데 name, hp, speed 속성과 move 메서드는 부모 클래스인 Character 클래스에서 그대로 상속받는다. 부모 클래스에 없는 attack만 자식 클래스에 추가한다. 그리고 자녀 클래스에서 사용할 move_attack이라는 메서드를 함수로 정의한다.

 

move_attack이라는 메서드처럼, 하위 클래스가 메서드를 재정의할 때 상위 클래스에서 상속받는 것 외에 자녀 클래스에서 사용할 메서드를 새롭게 구현하는 방법을 메서드 오버라이딩(Method overriding)이라고 한다.

병사 ‘army’(hp=200, speed= 50, attack=30)를 생산해서 10시 방향으로 공격해보자.

 

army = Attack("army", 200, 50, 30)     # army가 생성되었습니다.
army.move_attack("10시")               # army가 10시 방향으로 공격력 30으로 공격했습니다.

 

3. super ( )

 

super는 하위 클래스에서 상속의 대상인 부모 클래스의 속성과 메서드를 호출하는 내장 함수이다. 위의 예제에서 Character.__init__(self, name, hp, speed)처럼 하위 클래스가 부모 클래스에 이미 정의된 메서드나 속성을 가져오지만, 클래스 이름 없이 상위 클래스에서 속성이나 메서드를 가져올 때 super()를 이용한다. 클래스 명을 사용하지 않고 바로 위 클래스에서 속성과 메서드를 가져오기 때문에 클래스 명을 받는 self가 빠지고, super( ).__inti__(name, hp,** speed)와 같이 나타낸다.

반응형