WeniVooks

검색

견고한 파이썬

클래스란

1. 클래스란

클래스는 일종의 설계 도면 또는 템플릿입니다. 이 설계 도면을 통해 생산된 생산품을 인스턴스라 합니다. 클래스, 인스턴스는 중요한 용어이니 이 2개의 용어를 기억하며 글을 읽어주세요.

실제 개발된 예제를 보며 설명을 하겠습니다. 아래 게임을 잠시 해보고 오세요. 위니브에서 교육용으로 개발한 게임입니다.

Phaser를 활용한 게임

이 게임에는 주인공, 몹, 빌런이 있습니다. 이 주인공, 몹, 빌런에게는 모두 같은 데이터가 필요합니다. 체력과 마력, 공격력, 방어력같은 데이터 입니다. 또 같은 기능도 필요합니다. 공격을 하는 기능, 움직이는 기능, 아이템을 드랍하는 기능 등이요.

이러한 공통의 데이터와 기능을 한데 묶어서 클래스로 만들어 놓으면 편리합니다. 예를 들어 몹이 100마리가 있다해서 100개의 코드를 작성할 필요가 없습니다. 설계 도면(클래스)이 있다면 이것으로 100개의 몹(인스턴스)를 만들 수 있습니다.

class Character: # 클래스
    def __init__(hp, mp, power, drop_rate...(생략)):
        self.hp = hp # 데이터
        self.mp = mp # 데이터
        ...(생략)
 
    def move(self): # 기능
        ...(생략)
 
    def attack(self): # 기능
        ...(생략)
 
hero = Character(100, 100, 100, 0, ...(생략)) # 인스턴스
mob1 = Character(30, 30, 30, 0.8, ...(생략)) # 인스턴스
mob2 = Character(50, 50, 50, 0.5, ...(생략)) # 인스턴스
mob3 = Character(70, 70, 70, 0.3, ...(생략)) # 인스턴스
villain = Character(100, 100, 90, 0.1, ...(생략)) # 인스턴스
class Character: # 클래스
    def __init__(hp, mp, power, drop_rate...(생략)):
        self.hp = hp # 데이터
        self.mp = mp # 데이터
        ...(생략)
 
    def move(self): # 기능
        ...(생략)
 
    def attack(self): # 기능
        ...(생략)
 
hero = Character(100, 100, 100, 0, ...(생략)) # 인스턴스
mob1 = Character(30, 30, 30, 0.8, ...(생략)) # 인스턴스
mob2 = Character(50, 50, 50, 0.5, ...(생략)) # 인스턴스
mob3 = Character(70, 70, 70, 0.3, ...(생략)) # 인스턴스
villain = Character(100, 100, 90, 0.1, ...(생략)) # 인스턴스

게임뿐만 아니라 파이썬으로 웹 서비스를 쉽게 만들어주는 대표적인 프레임워크 장고(Django)에서는 게시물이나 User도 아래와 같은 양식으로 개발합니다.

# 단순화 시키긴 했으나 실제 아래와 같이 만듭니다.
class 게시물설계도: # 클래스
    _id = int()
    title = str()
    contents = str()
    author = str()
    create_time = str()
    update_time = str()
    view_count = int()
    last_connect_location = str()
    last_connect_time = str()
 
    def __str__(self): # 매직메서드
        ...(생략)
 
    def change_update_time(): # 메서드
        ...(생략)
 
게시물1 = 게시물설계도() # 인스턴스
게시물2 = 게시물설계도() # 인스턴스
# 단순화 시키긴 했으나 실제 아래와 같이 만듭니다.
class 게시물설계도: # 클래스
    _id = int()
    title = str()
    contents = str()
    author = str()
    create_time = str()
    update_time = str()
    view_count = int()
    last_connect_location = str()
    last_connect_time = str()
 
    def __str__(self): # 매직메서드
        ...(생략)
 
    def change_update_time(): # 메서드
        ...(생략)
 
게시물1 = 게시물설계도() # 인스턴스
게시물2 = 게시물설계도() # 인스턴스

2. 인스턴스 만들어보기

클래스를 만들기 위해서는 먼저 인스턴스를 상상해야 합니다. 설계 도면을 만들기 위해서는 우리가 바라는 모습을 구체화 해야 하기 때문입니다. 구체화 한 모습은 '설계 도면'이 아니라 '생산된 생산품'의 모습일 것입니다.

우선 우리는 한 게임의 '자동차'를 만든다고 가정해보겠습니다. 자동차에는 최대 속도, 최대 탑승객, 기어 등의 데이터가 있을 것입니다. 또한 출발, 정지 등의 기능이 있을 것입니다. 물론 더 많은 데이터와 기능이 있을 수 있지만, 여기서는 간단하게 설명하기 위해 이정도로만 가정하겠습니다.

데이터(멤버, 애트리뷰트) # 클래스 내 변수로 선언됩니다. 이것을 멤버 또는 애트리뷰트라고 합니다.
  * 클래스로 만들어진 자동차에 수
  * 최대 속도
  * 최대 탑승객
 
기능(메서드) # 클래스 내 함수로 선언됩니다. 이것을 메서드라고 합니다.
  * 출발
  * 정지
데이터(멤버, 애트리뷰트) # 클래스 내 변수로 선언됩니다. 이것을 멤버 또는 애트리뷰트라고 합니다.
  * 클래스로 만들어진 자동차에 수
  * 최대 속도
  * 최대 탑승객
 
기능(메서드) # 클래스 내 함수로 선언됩니다. 이것을 메서드라고 합니다.
  * 출발
  * 정지

이렇게 정의된 설계 도면을 실제 코드로 작성해봅시다. 설계 도면이 나왔으니 생산품도 함께 만들어보도록 하겠습니다.

class Car: # 차에 설계 도면 또는 차 공장, 클래스 count = 0 # 멤버 또는 애트리뷰트 max_speed = 300 # 멤버 또는 애트리뷰트 max_people = 5 # 멤버 또는 애트리뷰트 def start(self): # 메서드 print('차가 출발합니다!') def stop(self): # 메서드 print('차가 멈췄습니다!') # 공장에서 생산된 자동차 modelx, modely 인스턴스 modelx = Car() # 인스턴스 = 클래스() modely = Car() modelx.start() modelx.stop()

이렇게 정의된 class를 가지고 modelx, modely를 생성해보았습니다. 여기서 클래스와 인스턴스를 선언하는 형태에 대해 살펴보겠습니다.

class ClassName:
    pass
class ClassName:
    pass
instance = ClassName()
instance = ClassName()

위와 같은 양식으로 클래스와 인스턴스를 생성할 수 있습니다.

3. 자료형의 정체

위 예제에서 dot을 통해 멤버와 메서드에 접근할 수 있다는 것을 확인했습니다.

models.start()
models.stop()
models.start()
models.stop()

이러한 형태를 앞에서 많이 보았습니다.

l = [1, 2, 3] type(l) dir(l) l.append(4) l

바로 위와 같은 형태입니다. 이처럼 우리는 int, float, str과 같은 새로운 Car라는 type을 만들고 있는 것입니다.

print(type(models)) print(dir(models))

우리가 앞에서 많이 사용했었던 코드입니다.

<class '__main__.Car'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'car_gear', 'max_people', 'max_speed', 'start', 'stop']
<class '__main__.Car'>
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'car_gear', 'max_people', 'max_speed', 'start', 'stop']

우리가 선언하지 않아도 선언되는 되는 많은 매직 메서드와 메서드, 멤버가 있는 것을 확인할 수 있습니다. 여기서 파이썬을 관통하는 하나의 개념을 확인할 수 있습니다.

x = int(3) print(type(x))
<class 'int'>
<class 'int'>

여기서 x의 정체를 다시 한 번 생각해볼 필요가 있습니다. x를 int형이라고 말하는 것도 물론 맞는 얘기이고, x가 3이라고 말하는 것도 맞는 얘기이지만 x는 int class의 인스턴스라고 얘기한다면 더 정확한 표현이 될 것입니다.

x = int(3) isinstance(x, int) # 출력: True
class Car: pass modelx = Car() isinstance(modelx, Car) # 출력: True

우리가 클래스의 인스턴스를 만들 때 클래스명을 써 넣는 반면 아래 코드는 클래스명을 쓰지 않았습니다. 이는 파이썬이 내부적으로 3을 int class의 인스턴스로 만들어주기 때문입니다. 아래 2개의 코드는 동등한 결과를 만들어냅니다.

x = 3 # x는 int형 3입니다. 3은 int class의 인스턴스입니다.
# x = int(3) # x는 int형 3입니다. 3은 int class의 인스턴스입니다.
x = 3 # x는 int형 3입니다. 3은 int class의 인스턴스입니다.
# x = int(3) # x는 int형 3입니다. 3은 int class의 인스턴스입니다.
{"packages":["numpy","pandas","matplotlib","lxml"]}
10장 클래스10.2 클래스를 왜 써야 하는가?