객체지향의 세계에 발을 들일 때 가장 먼저 마주치고, 또 가장 많이 헷갈려하는 두 가지 핵심 단어가 있습니다. 바로 '클래스(Class)'와 '객체(Object)'입니다. 많은 비전공자가 이 두 개념의 차이를 모호하게 이해한 채 코드를 작성하다가, 인스턴스화 과정이나 메모리 구조에서 혼란을 겪고 중도 포기하곤 합니다.

저 역시 초보 시절, 클래스와 객체를 단순히 똑같은 대상을 부르는 다른 이름 정도로 오해해서 변수 할당 과정에서 수많은 에러를 냈던 기억이 있습니다. 오늘은 나만의 맞춤형 데이터 타입을 만들어내는 설계도인 클래스의 원리와, 이를 바탕으로 실체화되는 객체의 차이점을 명확하게 정리해 드립니다.


1. 클래스와 객체의 가장 확실한 비유: 설계도와 제품

클래스와 객체의 관계를 가장 쉽게 이해하는 방법은 '붕어빵 틀과 붕어빵' 또는 '건축 설계도와 실제 건물'로 비유하는 것입니다.

  • 클래스 (Class): 객체를 만들어내기 위한 '틀'이자 '설계도'입니다. 변수(속성)와 함수(메서드)가 어떤 모습으로 존재해야 하는지 정의해 둔 규격일 뿐, 그 자체로 실재하는 데이터는 아닙니다.

  • 객체 (Object / Instance): 클래스라는 설계도를 바탕으로 메모리(RAM) 상에 실제로 생성된 실체입니다. 각 객체는 자신만의 고유한 데이터를 가지며 독립적으로 존재합니다.

우리가 파이썬에서 기본으로 사용하는 int(정수), str(문자열), list(리스트) 역시 파이썬 개발자들이 미리 만들어둔 '기본 클래스'입니다. 우리가 a = 10이라고 변수를 만들 때, int라는 클래스를 기반으로 하나의 정수 객체를 생성하여 사용하고 있었던 셈입니다.


2. 클래스 정의하기: 속성(Attribute)과 메서드(Method)

파이썬에서 클래스를 정의할 때는 class 키워드를 사용하며, 클래스 이름은 관례적으로 첫 글자를 대문자로 쓰는 파스칼케이스(PascalCase)를 적용합니다.

클래스 내부에는 크게 두 가지 요소가 들어갑니다.

  1. 속성 (Attribute): 객체가 가지는 상태나 데이터 (변수)

  2. 메서드 (Method): 객체가할 수 있는 동작이나 기능 (함수)

Python
# 회원(Member) 정보를 다루기 위한 나만의 맞춤형 클래스 설계
class Member:
    # 회원 정보를 출력하는 메서드(기능)
    def display_info(self):
        print(f"회원 이름: {self.name}, 포인트: {self.point}점")

위의 코드처럼 클래스를 정의한 상태는 아직 종이 위에 설계도를 그려둔 것에 불과합니다. 실제로 실행해도 메모리상에는 아무런 회원 데이터가 생기지 않습니다.


3. 객체 생성(인스턴스화)과 self 키워드의 비밀

이제 작성한 설계도를 바탕으로 실제 작동하는 객체를 메모리에 찍어내 보겠습니다.

Python
# 1. Member 클래스를 기반으로 두 개의 독립된 객체 생성
user1 = Member()
user2 = Member()

# 2. 각 객체에 속성(데이터) 부여하기
user1.name = "김파이"
user1.point = 1500

user2.name = "이객체"
user2.point = 3000

# 3. 객체의 메서드 호출
user1.display_info()  # 출력: 회원 이름: 김파이, 포인트: 1500점
user2.display_info()  # 출력: 회원 이름: 이객체, 포인트: 3000점

여기서 self는 무엇을 의미할까요?

초보자가 클래스를 작성할 때 가장 생소해하는 부분이 바로 메서드의 첫 번째 매개변수로 들어가는 self입니다.

self는 "현재 이 메서드를 호출하고 있는 객체 자기 자신"을 가리키는 파이썬만의 약속입니다. user1.display_info()를 실행하면, 파이썬 내부적으로는 Member.display_info(user1)과 같이 호출한 객체를 self 자리에 자동으로 전달합니다.

따라서 self.name은 "다른 사람이 아닌, 바로 '나(user1)'의 name 속성값을 가져오라"는 뜻이 됩니다. 이 self 덕분에 하나의 클래스로 수백 개의 객체를 만들어도 데이터가 서로 섞이지 않고 자기 자신의 값을 정확히 찾아갈 수 있습니다.


4. 나만의 데이터 타입을 만든다는 것의 진짜 의미

단순히 list나 dict(딕셔너리)를 쓰면 되지, 왜 굳이 복잡하게 클래스를 직접 설계해야 할까요?

딕셔너리로 회원 데이터를 다루면 user = {"name": "김파이", "poin": 1500} 처럼 키(Key) 이름에 오타(poin)가 나도 코드가 실행되기 전까지 오류를 잡기 어렵습니다. 또한 데이터와 그 데이터를 처리하는 함수가 따로 놀게 됩니다.

반면 클래스를 활용해 Member라는 나만의 데이터 타입을 만들어두면, 회원 데이터와 관련된 모든 로직을 단단하게 묶어 관리할 수 있습니다. 입력값 검증, 포인트 차감, 등급 계산 등의 기능을 객체 내부에 숨겨두고 외부에선 user1.use_point(500)처럼 깔끔한 명령만 내리면 되므로 전체 프로그램의 안정성이 비약적으로 상승합니다.

핵심요약

  • 클래스(Class)는 객체를 생성하기 위한 변수와 메서드의 설계도이며, 객체(Object)는 이 설계도를 바탕으로 메모리에 실체화된 데이터입니다.

  • 메서드 내부의 self 키워드는 현재 해당 동작을 수행하고 있는 객체 자기 자신을 가리키는 필수 매개변수입니다.

  • 클래스를 설계하여 나만의 데이터 타입을 만들면 관련 데이터와 기능을 하나로 묶어 오타 및 데이터 오용 버그를 구조적으로 예방할 수 있습니다.