[바로바로 파이썬 08] 클래스와 인스턴스
이번 장에서는 파이썬 문법의 큰 산인 클래스를 공부합니다. 클래스는 데이터와 기능, 즉 지금까지 배운 자료형과 함수를 하나로 묶어 관리할 수 있는 설계도입니다. 처음에는 낯설겠지만 코드를 직접 실행하다 보면 조금씩 감이 잡힐 겁니다. 천천히 시작해봅시다.
클래스와 인스턴스 이해하기
파이썬에서 클래스는 class 키워드로 만듭니다. 클래스 안에는 클래스 변수, 인스턴스 변수, 메서드 등을 정의할 수 있습니다. 이렇게 만든 클래스는 설계도 역할을 합니다. 하지만 설계도만으로는 충분하지 않습니다. 설계도 자체가 실제 제품이 아닌 것처럼, 이를 바탕으로 실제 제품을 만드는 과정이 필요합니다. 이처럼 클래스를 바탕으로 실제로 사용할 수 있는 실체를 만드는 것을 ‘인스턴스화한다’라고 하며, 이렇게 만들어진 실체를 ‘인스턴스’라고 합니다. 우선 다음 코드를 입력하여 실행해보면서 이 의미에 대해 천천히 알아가봅시다.
Character라는 이름의 클래스를 선언하는 코드입니다. 다시 말해 캐릭터를 만들기 위한 설계도를 정의한 것이죠. 이 아래에 들여쓴 코드 블록은 모두 Character 클래스에 속합니다.
인스턴스가 만들어지는 순간 자동으로 실행되는 메서드입니다. 클래스를 설계도에 비유했으니 굳이 이어서 비유하자면 설계도에 ‘이 설계도로 제품을 만드는 순간 이것을 실행하세요’라고 적어둔 것과 같습니다. 이때 self가 붙은 self.name, self.health 변수를 인스턴스 변수라고 합니다.
생김새는 함수와 같지만 클래스 안에 정의되어 있으므로 메서드라고 부릅니다. 이 메서드는 인스턴스의 이름과 체력을 출력합니다. 여전히 인스턴스라는 말이 낯설 수 있지만 일단 넘어갑시다.
Character 클래스를 바탕으로 인스턴스를 생성하는 부분입니다. 바로 이 시점에 설계도(클래스)로부터 실제 인스턴스가 만들어집니다. Character("슬라임", 30)처럼 데이터가 다른 인스턴스를 만들기도 합니다.
정리하면 ➊ 클래스라는 설계도에 ➋ 인스턴스 변수와 ➌ 메서드를 정의하고, ➍ 그 설계도를 바탕으로 필요한 만큼 인스턴스를 만들어 사용하는 것이 클래스의 핵심입니다.
그림으로 이해하는 클래스와 인스턴스의 관계
다음은 앞에서 작성한 코드를 그림으로 그려본 것입니다. 그림을 통해 클래스와 인스턴스의 관계를 이해합시다.
➊ 그림을 보면 Character 클래스라는 설계도를 바탕으로 용사와 슬라임을 만들고 있습니다.
➋ 이때 용사와 슬라임은 각각 Character 클래스의 인스턴스인 것을 알 수 있죠. 각 인스턴스를 생성할 때 이름과 체력을 다르게 지정했습니다.
➌ 두 인스턴스는 모두 Character 클래스를 바탕으로 만들어졌기 때문에 show_status( ) 메서드를 사용할 수 있습니다.
➍ 따라서 두 인스턴스에서 각각 show_status( ) 메서드를 호출하면 자신의 이름과 체력을 출력합니다.
__init__( ) 메서드의 역할 알아보기
파이썬에는 이름 앞뒤에 밑줄 두 개(__)가 붙은 특별한 메서드가 있는데, 이를 특수 메서드special method라고 합니다. 흔히 매직 메서드magic method라고도 부르며, 특정 동작이 일어날 때 파이썬이 자동으로 호출합니다. __init__( ) 메서드는 인스턴스가 생성되는 순간 실행된다고 했습니다. __init__( ) 메서드의 동작 방식에 집중하기 위해 다음 예제를 실습해봅시다.
실행 결과를 보면 __init__( ) 메서드를 직접 실행하지 않았지만 Dog("초코", 3)과 같이 인스턴스를 만드는 과정에서 __init__( ) 메서드가 자동으로 호출됩니다. 이때 메서드 내부의 코드 블록이 실행되면서 '초코 강아지 등록 완료'가 출력됩니다. 그다음 self.name = name, self.age = age에 의해 "초코", 3도 저장됩니다.
self의 역할 알아보기
이제 self의 역할을 말끔하게 이해할 차례입니다. 인스턴스가 생성될 때 __init__( ) 메서드가 무조건 실행된다면 그 안에서 self는 무슨 역할을 할까요? 바로 ‘생성된 인스턴스’를 의미합니다.
클래스는 인스턴스를 만들기 위한 설계도이므로 어떤 인스턴스가 만들어질지 미리 알 수 없습니다. 클래스 안에 단순히 name, age라고만 작성하면 누구의 이름이고 나이인지 구분할 수 없습니다. 그래서 self.name, self.age처럼 작성하여 ‘앞으로 만들어질 각 인스턴스의 이름과 나이’를 나타냅니다.
코드로 살펴보면 self.name = name은 ‘전달받은 name의 값을 현재 생성되는 인스턴스의 self.name에 저장하라’는 뜻입니다. choco에 저장할 인스턴스를 만들 때 "초코"가 name으로 전달되므로 해당 인스턴스의 self.name에 "초코"가 저장됩니다. 메서드를 호출할 때도 마찬가지입니다. hero.show_status( )처럼 점 앞에 쓴 인스턴스가 그대로 self로 전달됩니다. 따라서 같은 메서드를 호출하더라도 각 인스턴스에 저장된 서로 다른 값을 사용할 수 있습니다. 이를 인스턴스 변수라고 부릅니다.
이제 앞에서 배운 내용을 다시 연습하며 내 것으로 다져보겠습니다. 이번에는 게임 아이템을 클래스로 표현해보겠습니다. 코드가 여러 줄이므로 파이썬 파일로 저장하여 실행하는 방식으로 연습하겠습니다. 다음 코드를 입력한 뒤 실행해봅시다.
➊ Item이라는 이름의 클래스를 만들었습니다. 게임 아이템을 만들기 위한 설계도를 정의한 셈입니다.
➋ __init__( ) 메서드에서 name과 price 값을 받아 self.name, self.price에 저장했습니다. 이렇게 저장한 값은 각 인스턴스가 자기만의 데이터로 가지게 됩니다.
➌ show_info( ) 메서드는 아이템의 이름과 가격을 출력합니다.
➍ Item("체력 물약", 50), Item("나무 검", 120)을 실행해서 서로 다른 두 인스턴스를 만들었습니다.
➎ 각 인스턴스에서 show_info( ) 메서드를 호출하면 자기 인스턴스에 저장된 name과 price를 사용해 정보를 출력합니다.
이번에는 하나의 Student 클래스로 두 학생을 만들고, self가 각 인스턴스를 가리켜 학생마다 자신의 이름과 점수를 출력하는 과정을 확인해봅시다.
➊ Student라는 이름의 클래스를 만들었습니다.
➋ __init__( ) 메서드에서 name과 score를 받아 self.name, self.score에 저장했습니다.
➌ introduce( ) 메서드는 인스턴스가 가진 이름과 점수를 출력합니다.
➍ Student("민수", 85), Student("지유", 92)를 실행해서 서로 다른 두 인스턴스를 만들었습니다.
➎ minsu.introduce( )를 실행하면 self는 minsu를 가리키고, jiyu.introduce( )를 실행하면 self는 jiyu를 가리킵니다. 따라서 같은 메서드를 실행해도 각 인스턴스에 저장된 서로 다른 값이 출력됩니다.
이 정도면 클래스와 인스턴스, __init__( ), self, 메서드가 어떤 역할을 하고 어떻게 동작하는지 이해할 수 있을 것입니다. 그럼 다음으로 넘어가봅시다.
