오늘은 파이썬의 클래스(class)에 대해 알아보겠습니다. 학교에서 듣는 수업 시간이 아니라, 프로그래밍에서 말하는 클래스입니다.
프로그래밍에서 클래스는 고유한 정의를 가지고 있습니다. 클래스란 개발자가 객체(object)를 만들기 위해 작성하는 설계도입니다. 즉, 객체에 어떤 데이터를 저장할 수 있는지, 그 객체에 어떤 동작(메서드)을 수행할 수 있는지 정의해 줍니다.
파이썬은 객체 지향 프로그래밍(Object-Oriented Programming) 언어입니다. 이는 객체와 클래스를 활용해 데이터를 저장하고 구조화하는 개발 방식을 사용한다는 의미입니다.
객체 지향 프로그래밍이 중요한 이유
객체 지향 접근 방식은 코드의 반복을 크게 줄여 주기 때문에 코드를 더 읽기 쉽고 유지 보수하기 편하게 만들어 줍니다. 클래스와 객체는 자바(Java), 파이썬(Python), C++ 등 많은 프로그래밍 언어에서 핵심적인 역할을 담당합니다.
이 글에서는 클래스가 무엇인지, 어떻게 동작하는지, 그리고 파이썬에서 클래스를 어떻게 선언하는지 예제와 함께 차근차근 살펴보겠습니다.
클래스란 무엇인가?
클래스는 객체를 정의하기 위한 설계도입니다.
집을 짓기 위한 건축 도면을 상상해 보세요. 그 도면에는 문이 어디에 들어갈지, 창문이 어디에 위치할지 등이 표시되어 있습니다. 프로그래밍의 클래스도 마찬가지입니다. 클래스는 객체 안에 어떤 데이터를 저장할 수 있고, 어떤 기능을 수행할 수 있는지 미리 정의해 둔 틀이라고 할 수 있습니다.
클래스는 class 키워드를 사용하여 정의합니다. 간단한 예제로, 플레이어(Player)라는 이름의 클래스를 만들어 두 개의 함수를 포함시켜 보겠습니다.
class Player:
"""플레이어를 위한 클래스입니다"""
name = "Luke"
def wield_sword(self):
print("검을 뽑아 들었습니다.")
def drink_health_potion(self):
print("체력 회복 물약을 마셨습니다.")
속성과 메서드
위 클래스는 비디오 게임 속 플레이어를 표현합니다. 클래스 안에는 속성(attribute)과 메서드(method)가 함께 들어 있습니다. 클래스 내부에 선언된 속성은 흔히 인스턴스 변수(instance variable)라고 부릅니다.
한 메서드는 검을 뽑아 드는 동작을, 다른 메서드는 체력 회복 물약을 마시는 동작을 수행합니다. 또한 클래스에는 name이라는 하나의 변수가 있으며, 이곳에 플레이어의 기본 이름이 저장됩니다.
self의 역할
코드에서 self라는 단어가 여러 번 사용된 것을 눈치채셨나요? self는 이름 그대로 클래스 자기 자신을 나타냅니다. self에는 해당 클래스에 저장된 모든 값이 담겨 있기 때문에, 메서드 안에서 클래스 내부의 값들을 자유롭게 접근하고 사용할 수 있습니다.
그런데 이 코드를 실행하면 아무 일도 일어나지 않습니다. 왜일까요? 앞서 클래스는 '설계도'라고 했던 것이 바로 이유입니다. 설계도만으로는 아무것도 만들 수 없듯이, 실제로 유용하게 사용하려면 설계도를 가지고 무언가를 만들어야 합니다.
객체란 무엇인가?
객체는 클래스의 단 하나의 실체(instance)입니다. 클래스가 제공하는 설계도를 바탕으로 만들어집니다.
이제 우리 게임에 새로운 플레이어 'Luke'를 위한 객체를 만들어 보겠습니다.
luke = Player()
방금 'Luke'라는 객체를 생성했습니다. 이 객체는 이제 클래스 안에 저장된 모든 데이터와 메서드에 접근할 수 있습니다.
luke = Player()
print(luke.name)
luke.wield_sword()
실행 결과:
Luke 검을 뽑아 들었습니다.
점 표기법(Dot Notation)으로 속성에 접근하기
위 코드에서는 Luke 객체의 name 속성 값을 출력했습니다. 클래스의 속성에 접근하려면 객체 이름 → 점(.) → 접근하려는 속성 이름 순서로 작성하면 됩니다. 이러한 방식을 흔히 점 표기법(dot notation)이라고 부릅니다.
기본적으로 name 값은 Luke로 설정되어 있었습니다. 이 값을 변경하는 방법은 잠시 후에 다루겠습니다.
또한 wield_sword() 메서드도 호출했습니다. 메서드가 호출되면서 Player 클래스 안에 정의된 해당 메서드의 내용이 실행되었고, 콘솔에 "검을 뽑아 들었습니다."라는 메시지가 출력된 것입니다.
하나의 클래스로 원하는 만큼 많은 객체를 만들 수 있다는 점이 바로 클래스가 강력한 이유입니다. 클래스에 저장된 메서드와 기본값들을 여러 객체에서 재사용할 수 있습니다.
클래스 생성자(Constructor)
생성자(constructor)를 사용하면 클래스 내부의 데이터를 초기화할 수 있습니다. 생성자 메서드는 특정 클래스의 객체를 선언하는 순간 즉시 실행됩니다.
생성자의 이름은 __init__()입니다. 코드에서 밑줄 두 개(__)로 감싸진 함수를 본 적이 있을 겁니다. 이런 함수들은 미리 정해진 목적이 있다 하여 특수 함수(special function)라고 불립니다. 여기서 __init__의 목적은 클래스를 초기화하는 것입니다.
앞서 만든 Player 클래스 맨 위에 다음 메서드를 추가해 보겠습니다.
def __init__(self):
print("캐릭터가 생성되었습니다.")
이 메서드는 반드시 클래스 내의 다른 변수나 메서드보다 먼저 위치해야 합니다. 이제 앞서 작성했던 메인 코드를 다시 실행해 보겠습니다.
luke = Player()
print(luke.name)
luke.wield_sword()
실행 결과:
캐릭터가 생성되었습니다. Luke 검을 뽑아 들었습니다.
메인 프로그램에서 __init__ 메서드를 직접 호출하지 않았는데도 실행되었습니다. 그 이유는 생성자는 클래스의 객체가 생성될 때 자동으로 실행되기 때문입니다.
생성자로 이름 동적으로 할당하기
앞서 클래스의 name 변수에 Luke라는 값을 고정해 두었습니다. 플레이어 이름이 항상 Luke라면 문제없지만, 플레이어마다 서로 다른 이름을 가질 수 있다면 비효율적입니다.
바로 이럴 때 생성자가 빛을 발합니다. 플레이어에게 이름을 할당할 수 있는 생성자를 만들어 보겠습니다.
class Player:
def __init__(self, name):
self.name = name
이 코드를 통해 각 Player 객체에 매개변수를 전달할 수 있게 되었으며, 이 매개변수가 곧 플레이어의 이름이 됩니다. 이어서 플레이어의 이름을 알려주는 메서드도 추가해 보겠습니다.
class Player:
def __init__(self, name):
self.name = name
def get_name(self):
print("당신의 이름은 " + self.name + "입니다.")
'Leah'라는 이름을 가진 새로운 Player 객체를 만들어 보겠습니다.
leah = Player("Leah")
leah.get_name()
실행 결과:
당신의 이름은 Leah입니다.
객체의 name 변수에 Leah라는 값이 할당되었습니다. 따라서 클래스 내 어디서든 이 값을 참조하면 Leah라는 결과를 얻게 됩니다. 생성자는 객체를 생성하는 순간 자동으로 실행되기 때문에 별도로 호출할 필요가 없습니다.
이후 get_name() 메서드를 호출하면 해당 플레이어의 이름이 출력됩니다.
여러 개의 매개변수 사용하기
클래스에는 원하는 만큼 매개변수를 추가할 수 있습니다.
class Player:
def __init__(self, name, player_type):
self.name = name
self.player_type = player_type
def get_name(self):
print("당신의 이름은 " + self.name + "입니다.")
def get_player_type(self):
print(self.name + "은(는) " + self.player_type + "입니다.")
이 예제에서 Player 클래스는 두 개의 매개변수를 받습니다. 하나는 플레이어의 이름(name)이고, 다른 하나는 플레이어의 직업(player_type)입니다. 이 클래스의 객체를 만들어 확인해 보겠습니다.
leah = Player("Leah", "Mage")
leah.get_name()
leah.get_player_type()
실행 결과:
당신의 이름은 Leah입니다. Leah은(는) Mage입니다.
생성자를 통해 지정한 두 초기 값이 모두 클래스 내부에서 정상적으로 접근 가능함을 확인할 수 있습니다.
마무리: 클래스와 객체의 핵심 정리
클래스를 활용하면 코드의 반복을 크게 줄일 수 있습니다. 한 번 클래스를 정의해 두면, 그 구조를 재사용하여 원하는 만큼 많은 객체를 만들 수 있습니다. 반복이 줄어들면 코드를 읽기가 쉬워지고, 자연스럽게 유지 보수도 수월해집니다.
핵심 내용을 요약하면 다음과 같습니다.
- 클래스: 객체를 만들기 위한 설계도로, 데이터(속성)와 동작(메서드)을 정의한다.
- 객체: 클래스를 기반으로 생성된 실체(instance)이다.
- self: 클래스 자기 자신을 나타내며, 메서드 안에서 클래스 내부 값에 접근할 수 있게 해준다.
- 생성자(__init__): 객체가 생성될 때 자동으로 실행되어 데이터를 초기화한다.
이제 여러분도 전문가처럼 나만의 파이썬 클래스를 작성할 준비가 되었습니다!